Skip to content

Commit 8fd9671

Browse files
New feature: send/recv message implementation added to network stack
1 parent 81aaef4 commit 8fd9671

File tree

14 files changed

+525
-31
lines changed

14 files changed

+525
-31
lines changed

connectivity/cellular/include/cellular/framework/AT/AT_CellularStack.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ class AT_CellularStack : public NetworkStack {
8888

8989
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data);
9090

91+
// FIXME
92+
nsapi_size_or_error_t socket_sendmsg(nsapi_socket_t handle, const SocketAddress &address,
93+
const void *data, nsapi_size_t size,
94+
nsapi_msghdr_t *control, nsapi_size_t control_size) override
95+
{
96+
return NSAPI_ERROR_UNSUPPORTED;
97+
}
98+
99+
nsapi_size_or_error_t socket_recvmsg(nsapi_socket_t handle, SocketAddress *address,
100+
void *data, nsapi_size_t size,
101+
nsapi_msghdr_t *control, nsapi_size_t control_size) override
102+
{
103+
return NSAPI_ERROR_UNSUPPORTED;
104+
}
105+
91106
protected:
92107
class CellularSocket {
93108
public:

connectivity/lwipstack/include/lwipstack/LWIPStack.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,27 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
449449
*/
450450
nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
451451
const void *data, nsapi_size_t size) override;
452+
453+
/** Send a packet with ancillary data over a UDP socket
454+
*
455+
* Sends data to the specified address. Returns the number of bytes
456+
* sent from the buffer.
457+
*
458+
* This call is non-blocking. If sendto would block,
459+
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
460+
*
461+
* @param handle Socket handle
462+
* @param address The SocketAddress of the remote host
463+
* @param data Buffer of data to send to the host
464+
* @param size Size of the buffer in bytes
465+
* @param control Ancillary data storage
466+
* @param control_size Size of the Ancillary data in bytes
467+
* @return Number of sent bytes on success, negative error
468+
* code on failure
469+
*/
470+
nsapi_size_or_error_t socket_sendmsg(nsapi_socket_t handle, const SocketAddress &address,
471+
const void *data, nsapi_size_t size,
472+
nsapi_msghdr_t* control, nsapi_size_t control_size) override;
452473

453474
/** Receive data over a TCP socket
454475
*
@@ -493,6 +514,7 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
493514
* This call is non-blocking. If recvfrom would block,
494515
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
495516
*
517+
* It uses socket_recvmsg with zero ancillary data.
496518
* @param handle Socket handle
497519
* @param address Destination for the source address or NULL
498520
* @param buffer Destination buffer for data received from the host
@@ -503,6 +525,27 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
503525
nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
504526
void *buffer, nsapi_size_t size) override;
505527

528+
/** Receive a packet with ancillary data over a UDP socket
529+
*
530+
* Receives data and stores the source address in address if address
531+
* is not NULL. Returns the number of bytes received into the buffer.
532+
*
533+
* This call is non-blocking. If recvfrom would block,
534+
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
535+
*
536+
* @param handle Socket handle
537+
* @param address Destination for the source address or NULL
538+
* @param buffer Destination buffer for data received from the host
539+
* @param size Size of the buffer in bytes
540+
* @param control Ancillary data storage
541+
* @param control_size Size of the Ancillary data in bytes
542+
* @return Number of received bytes on success, negative error
543+
* code on failure
544+
*/
545+
nsapi_size_or_error_t socket_recvmsg(nsapi_socket_t handle, SocketAddress *address,
546+
void *data, nsapi_size_t size,
547+
nsapi_msghdr_t* control, nsapi_size_t control_size) override;
548+
506549
/** Register a callback on state change of the socket
507550
*
508551
* The specified callback will be called on state changes such as when

connectivity/lwipstack/include/lwipstack/lwipopts.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@
311311

312312
#endif
313313

314+
// FIXME: Add compile time configuration and define conditionaly
315+
#define LWIP_NETBUF_RECVINFO 1
316+
314317
// Make sure we default these to off, so
315318
// LWIP doesn't default to on
316319
#ifndef LWIP_ARP

connectivity/lwipstack/source/LWIPStack.cpp

Lines changed: 117 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
* limitations under the License.
1616
*/
1717
#include "nsapi.h"
18+
#include "netsocket/MsgHeader.h"
1819
#include "mbed_interface.h"
1920
#include "mbed_assert.h"
2021
#include "Semaphore.h"
21-
#include <stdio.h>
2222
#include <stdbool.h>
2323
#include <string.h>
2424

@@ -37,6 +37,7 @@
3737
#include "lwip/raw.h"
3838
#include "lwip/netif.h"
3939
#include "lwip/lwip_errno.h"
40+
#include "lwip/ip_addr.h"
4041
#include "lwip-sys/arch/sys_arch.h"
4142

4243
#include "LWIPStack.h"
@@ -439,24 +440,109 @@ nsapi_size_or_error_t LWIP::socket_recv(nsapi_socket_t handle, void *data, nsapi
439440
}
440441

441442
nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAddress &address, const void *data, nsapi_size_t size)
443+
{
444+
return socket_sendmsg(handle, address, data, size, NULL, 0);
445+
}
446+
447+
nsapi_size_or_error_t LWIP::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *data, nsapi_size_t size)
448+
{
449+
return socket_recvmsg(handle, address, data, size, NULL, 0);
450+
451+
}
452+
453+
nsapi_size_or_error_t LWIP::socket_recvmsg(nsapi_socket_t handle, SocketAddress *address,
454+
void *data, nsapi_size_t size,
455+
nsapi_msghdr_t *control, nsapi_size_t control_size)
442456
{
443457
struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
444-
ip_addr_t ip_addr;
458+
struct netbuf *buf;
459+
460+
err_t err = netconn_recv(s->conn, &buf);
461+
if (err != ERR_OK) {
462+
return err_remap(err);
463+
}
464+
465+
if (address) {
466+
nsapi_addr_t addr;
467+
convert_lwip_addr_to_mbed(&addr, netbuf_fromaddr(buf));
468+
address->set_addr(addr);
469+
address->set_port(netbuf_fromport(buf));
470+
}
471+
472+
if ((s->conn->flags & NETCONN_FLAG_PKTINFO) && control && control_size >= sizeof(nsapi_pktinfo_t)) {
473+
nsapi_pktinfo_t *pkt_info = reinterpret_cast<nsapi_pktinfo *>(control);
474+
// Not optimal but sufficient. It should help the caller in not iterating over
475+
// the control data structure
476+
control->len = control_size;
477+
control->level = NSAPI_SOCKET;
478+
control->type = NSAPI_PKTINFO;
479+
// retrieve the destination
480+
convert_lwip_addr_to_mbed(&pkt_info->ipi_addr, netbuf_destaddr(buf));
481+
// retrieve the interface id
482+
pkt_info->ipi_ifindex = buf->p->if_idx;
483+
}
484+
485+
u16_t recv = netbuf_copy(buf, data, (u16_t)size);
486+
netbuf_delete(buf);
487+
488+
return recv;
489+
}
490+
491+
nsapi_size_or_error_t LWIP::socket_sendmsg(nsapi_socket_t handle, const SocketAddress &address,
492+
const void *data, nsapi_size_t size,
493+
nsapi_msghdr_t *control, nsapi_size_t control_size)
494+
{
495+
struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
496+
ip_addr_t ip_addr = {};
497+
498+
// Used for backup the bound address if the packet must be sent from a specific address,
499+
ip_addr_t bound_addr = {};
500+
ip_addr_t src_addr = {};
501+
502+
nsapi_pktinfo_t *pkt_info = nullptr;
445503

446504
nsapi_addr_t addr = address.get_addr();
447505
if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
448506
return NSAPI_ERROR_PARAMETER;
449507
}
450-
struct netif *netif_ = netif_get_by_index(s->conn->pcb.ip->netif_idx);
508+
509+
// We try to extract the pktinfo from the header
510+
511+
if (control) {
512+
MsgHeaderIterator it(control, control_size);
513+
while (it.has_next()) {
514+
auto *hdr = it.next();
515+
if (hdr->level == NSAPI_SOCKET && hdr->type == NSAPI_PKTINFO) {
516+
pkt_info = reinterpret_cast<nsapi_pktinfo_t *>(hdr);
517+
break;
518+
}
519+
}
520+
}
521+
522+
if (pkt_info) {
523+
if (!convert_mbed_addr_to_lwip(&src_addr, &pkt_info->ipi_addr)) {
524+
return NSAPI_ERROR_PARAMETER;
525+
}
526+
}
527+
528+
struct netif *netif_ = nullptr;
529+
530+
if (pkt_info) {
531+
netif_ = netif_get_by_index(pkt_info->ipi_ifindex);
532+
} else {
533+
netif_ = netif_get_by_index(s->conn->pcb.ip->netif_idx);
534+
}
451535
if (!netif_) {
452536
netif_ = &default_interface->netif;
453537
}
538+
454539
if (netif_) {
455540
if ((addr.version == NSAPI_IPv4 && !get_ipv4_addr(netif_)) ||
456541
(addr.version == NSAPI_IPv6 && !get_ipv6_addr(netif_) && !get_ipv6_link_local_addr(netif_))) {
457542
return NSAPI_ERROR_PARAMETER;
458543
}
459544
}
545+
460546
struct netbuf *buf = netbuf_new();
461547

462548
err_t err = netbuf_ref(buf, data, (u16_t)size);
@@ -465,36 +551,29 @@ nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAdd
465551
return err_remap(err);
466552
}
467553

468-
err = netconn_sendto(s->conn, buf, &ip_addr, address.get_port());
469-
netbuf_delete(buf);
470-
if (err != ERR_OK) {
471-
return err_remap(err);
554+
// handle src destination if required
555+
if (pkt_info) {
556+
// Backup the bound address
557+
ip_addr_copy(bound_addr, s->conn->pcb.udp->local_ip);
558+
// replace it with the source address
559+
if (!ip_addr_isany(&src_addr)) {
560+
ip_addr_copy(s->conn->pcb.udp->local_ip, src_addr);
561+
}
472562
}
473563

474-
return size;
475-
}
564+
err = netconn_sendto(s->conn, buf, &ip_addr, address.get_port());
476565

477-
nsapi_size_or_error_t LWIP::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *data, nsapi_size_t size)
478-
{
479-
struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
480-
struct netbuf *buf;
566+
if (pkt_info) {
567+
// restore bound address
568+
ip_addr_copy(s->conn->pcb.udp->local_ip, bound_addr);
569+
}
481570

482-
err_t err = netconn_recv(s->conn, &buf);
571+
netbuf_delete(buf);
483572
if (err != ERR_OK) {
484573
return err_remap(err);
485574
}
486575

487-
if (address) {
488-
nsapi_addr_t addr;
489-
convert_lwip_addr_to_mbed(&addr, netbuf_fromaddr(buf));
490-
address->set_addr(addr);
491-
address->set_port(netbuf_fromport(buf));
492-
}
493-
494-
u16_t recv = netbuf_copy(buf, data, (u16_t)size);
495-
netbuf_delete(buf);
496-
497-
return recv;
576+
return size;
498577
}
499578

500579
int32_t LWIP::find_multicast_member(const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr)
@@ -687,6 +766,19 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
687766
}
688767
s->conn->pcb.ip->tos = (u8_t)(*(const int *)optval);
689768
return 0;
769+
770+
case NSAPI_PKTINFO:
771+
// FIXME: Turn NETCONN_FLAG_PKTINFO off by default
772+
if (optlen != sizeof(int)) {
773+
return NSAPI_ERROR_UNSUPPORTED;
774+
}
775+
if (*(const int *)optval) {
776+
s->conn->flags |= NETCONN_FLAG_PKTINFO;
777+
} else {
778+
s->conn->flags &= ~NETCONN_FLAG_PKTINFO;
779+
}
780+
return 0;
781+
690782
default:
691783
return NSAPI_ERROR_UNSUPPORTED;
692784
}

connectivity/nanostack/include/nanostack-interface/Nanostack.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,21 @@ class Nanostack : public OnboardNetworkStack, private mbed::NonCopyable<Nanostac
302302
*/
303303
nsapi_error_t getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) override;
304304

305+
// FIXME: Implement
306+
nsapi_size_or_error_t socket_sendmsg(nsapi_socket_t handle, const SocketAddress &address,
307+
const void *data, nsapi_size_t size,
308+
nsapi_msghdr_t *control, nsapi_size_t control_size) override
309+
{
310+
return NSAPI_ERROR_UNSUPPORTED;
311+
}
312+
313+
nsapi_size_or_error_t socket_recvmsg(nsapi_socket_t handle, SocketAddress *address,
314+
void *data, nsapi_size_t size,
315+
nsapi_msghdr_t *control, nsapi_size_t control_size) override
316+
{
317+
return NSAPI_ERROR_UNSUPPORTED;
318+
}
319+
305320
private:
306321

307322
/** Call in callback

connectivity/netsocket/include/netsocket/InternetDatagramSocket.h

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class InternetDatagramSocket : public InternetSocket {
3636
* nonblocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
3737
* immediately.
3838
*
39+
* It uses sendmsg with zero ancillary data
3940
* @param address The SocketAddress of the remote host.
4041
* @param data Buffer of data to send to the host.
4142
* @param size Size of the buffer in bytes.
@@ -60,7 +61,7 @@ class InternetDatagramSocket : public InternetSocket {
6061
* are accepted.
6162
*
6263
* @note recvfrom() is allowed write to address and data buffers even if error occurs.
63-
*
64+
* It uses recvmsg with zero ancillary data
6465
* @param address Destination for the source address or NULL.
6566
* @param data Destination buffer for RAW data to be received from the host.
6667
* @param size Size of the buffer in bytes.
@@ -74,6 +75,58 @@ class InternetDatagramSocket : public InternetSocket {
7475
nsapi_size_or_error_t recvfrom(SocketAddress *address,
7576
void *data, nsapi_size_t size) override;
7677

78+
/** Send datagram and ancillary data to the specified address.
79+
*
80+
* By default, sendto blocks until data is sent. If socket is set to
81+
* nonblocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
82+
* immediately.
83+
*
84+
* It uses sendmsg with zero ancillary data
85+
* @param address The SocketAddress of the remote host.
86+
* @param data Buffer of data to send to the host.
87+
* @param size Size of the buffer in bytes.
88+
* @param control Size of the buffer in bytes.
89+
* @param control_size Size of the buffer in bytes.
90+
* @retval NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
91+
* @retval NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
92+
* and send cannot be performed immediately.
93+
* @retval int Other negative error codes for stack-related failures.
94+
* See \ref NetworkStack::socket_send.
95+
*/
96+
nsapi_size_or_error_t sendmsg(const SocketAddress &address,
97+
const void *data, nsapi_size_t size,
98+
nsapi_msghdr_t* control, nsapi_size_t control_size) override;
99+
100+
101+
/** Receive a datagram with ancillary data and store the source address in address if it's not NULL.
102+
*
103+
* By default, recvfrom blocks until a datagram is received. If socket is set to
104+
* nonblocking or times out with no datagram, NSAPI_ERROR_WOULD_BLOCK
105+
* is returned.
106+
* Ancillary data is stored in msghdr struct
107+
* @note If the datagram is larger than the buffer, the excess data is silently discarded.
108+
*
109+
* @note If socket is connected, only packets coming from connected peer address
110+
* are accepted.
111+
*
112+
* @note recvfrom() is allowed write to address and data buffers even if error occurs.
113+
*
114+
* @param address Destination for the source address or NULL.
115+
* @param data Destination buffer for RAW data to be received from the host.
116+
* @param size Size of the buffer in bytes.
117+
* @param control Size of the buffer in bytes.
118+
* @param control_size Size of the buffer in bytes.
119+
* @retval int Number of received bytes on success.
120+
* @retval NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
121+
* @retval NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
122+
* and send cannot be performed immediately.
123+
* @retval int Other negative error codes for stack-related failures.
124+
* See \ref NetworkStack::socket_recv.
125+
*/
126+
nsapi_size_or_error_t recvmsg(SocketAddress *address,
127+
void *data, nsapi_size_t size,
128+
nsapi_msghdr_t *control, nsapi_size_t control_size) override;
129+
77130
/** Set the remote address for next send() call and filtering
78131
* of incoming packets. To reset the address, zero initialized
79132
* SocketAddress must be in the address parameter.

0 commit comments

Comments
 (0)