1+ /*
2+ MbedUdp.h - UDP implementation using mbed Sockets
3+ Copyright (c) 2021 Arduino SA. All right reserved.
4+
5+ This library is free software; you can redistribute it and/or
6+ modify it under the terms of the GNU Lesser General Public
7+ License as published by the Free Software Foundation; either
8+ version 2.1 of the License, or (at your option) any later version.
9+
10+ This library is distributed in the hope that it will be useful,
11+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+ Lesser General Public License for more details.
14+
15+ You should have received a copy of the GNU Lesser General Public
16+ License along with this library; if not, write to the Free Software
17+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+ */
19+
20+ #include " Arduino.h"
21+ #include " SocketWrapper.h"
22+ #include " api/Udp.h"
23+ #include " sys/socket.h"
24+ #include " zephyr/net/net_ip.h"
25+ #include " zephyr/net/net_if.h"
26+
27+ #include < list>
28+ #include < deque>
29+ #include < vector>
30+ #include < memory>
31+
32+ class ZephyrUDP : public arduino ::UDP {
33+ private:
34+ int _socket;
35+
36+ public:
37+ ZephyrUDP () : _socket(-1 ) {} // Constructor
38+ ~ZephyrUDP () {
39+ stop ();
40+ }
41+
42+ // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
43+ virtual uint8_t begin (uint16_t port) {
44+
45+ struct sockaddr_in addr;
46+ addr.sin_family = AF_INET;
47+ addr.sin_port = htons (port);
48+ addr.sin_addr .s_addr = INADDR_ANY;
49+
50+ _socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
51+
52+ zsock_ioctl (_socket, ZFD_IOCTL_FIONBIO);
53+
54+ if (::bind (_socket, (struct sockaddr *)&addr, sizeof (addr)) < 0 ) {
55+ ::close (_socket);
56+ _socket = -1 ;
57+ return false ;
58+ }
59+
60+ return true ;
61+ }
62+
63+ // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 if there are no sockets available to use
64+ virtual uint8_t beginMulticast (IPAddress ip, uint16_t port) {
65+ bool ret = begin (port);
66+ if (ret == false ) {
67+ return false ;
68+ }
69+
70+ struct sockaddr_in addr;
71+ addr.sin_family = AF_INET;
72+ addr.sin_addr .s_addr = ip;
73+
74+ net_if_ipv4_maddr_join (net_if_get_by_index (1 ), net_if_ipv4_maddr_add (net_if_get_by_index (1 ), (struct in_addr *)&addr));
75+ return true ;
76+ }
77+
78+ // Finish with the UDP socket
79+ virtual void stop () {
80+ if (_socket != -1 ) {
81+ ::close (_socket);
82+ _socket = -1 ;
83+ }
84+ }
85+
86+ // Sending UDP packets
87+
88+ // Start building up a packet to send to the remote host specific in ip and port
89+ // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
90+ virtual int beginPacket (IPAddress ip, uint16_t port) {
91+ _send_to_ip = ip;
92+ _send_to_port = port;
93+
94+ /* Make sure that the transmit data buffer is empty. */
95+ _tx_data.clear ();
96+ return true ;
97+ }
98+
99+ // Start building up a packet to send to the remote host specific in host and port
100+ // Returns 1 if successful, 0 if there was a problem resolving the hostname or port
101+ virtual int beginPacket (const char * host, uint16_t port) {
102+ // Resolve address
103+ struct addrinfo hints;
104+ struct addrinfo *res;
105+
106+ hints.ai_family = AF_INET;
107+ hints.ai_socktype = SOCK_DGRAM;
108+
109+ int resolve_attempts = 100 ;
110+ int ret;
111+
112+ while (resolve_attempts--) {
113+ ret = getaddrinfo (host, String (port).c_str (), &hints, &res);
114+
115+ if (ret == 0 ) {
116+ break ;
117+ } else {
118+ k_sleep (K_MSEC (1 ));
119+ }
120+ }
121+
122+ if (ret != 0 ) {
123+ return false ;
124+ }
125+
126+ return beginPacket (IPAddress (((sockaddr_in*)(res->ai_addr ))->sin_addr .s_addr ), port);
127+ }
128+
129+ // Finish off this packet and send it
130+ // Returns 1 if the packet was sent successfully, 0 if there was an error
131+ virtual int endPacket () {
132+ struct sockaddr_in addr;
133+ addr.sin_family = AF_INET;
134+ addr.sin_port = htons (_send_to_port);
135+ addr.sin_addr .s_addr = _send_to_ip;
136+ return ::sendto (_socket, _tx_data.data (), _tx_data.size (), 0 , (sockaddr*)&addr, sizeof (addr));
137+ }
138+
139+ // Write a single byte into the packet
140+ virtual size_t write (uint8_t data) {
141+ _tx_data.push_back (data);
142+ return 1 ;
143+ }
144+
145+ // Write size bytes from buffer into the packet
146+ virtual size_t write (uint8_t * buffer, size_t size) {
147+ std::copy (buffer, buffer + size, std::back_inserter (_tx_data));
148+ return size;
149+ }
150+
151+ // Write size bytes from buffer into the packet
152+ virtual size_t write (const uint8_t * buffer, size_t size) {
153+ std::copy (buffer, buffer + size, std::back_inserter (_tx_data));
154+ return size;
155+ }
156+
157+ using Print::write;
158+
159+ int parsePacket ()
160+ {
161+ struct sockaddr_in addr;
162+ socklen_t addrlen = sizeof (addr);
163+ uint8_t tmp_buf[512 ];
164+
165+ int ret = ::recvfrom (_socket, tmp_buf, sizeof (tmp_buf), 0 , (sockaddr*)&addr, &addrlen);
166+ if (ret > 0 )
167+ {
168+ auto pkt = std::make_shared<UdpRxPacket>(
169+ IPAddress (addr.sin_addr .s_addr ),
170+ ntohs (addr.sin_port ), tmp_buf, ret);
171+
172+ _rx_pkt_list.push_back (pkt);
173+
174+ // drop the oldest packet if the list is full
175+ if (_rx_pkt_list.size () > _rx_pkt_list_size) {
176+ _rx_pkt_list.pop_front ();
177+ }
178+ }
179+
180+ if (_rx_pkt_list.size ())
181+ {
182+ /* Discard UdpRxPacket object previously held by _rx_pkt
183+ * and replace it with the new one.
184+ */
185+ _rx_pkt = _rx_pkt_list.front ();
186+ _rx_pkt_list.pop_front ();
187+ return _rx_pkt->totalSize ();
188+ }
189+ else
190+ {
191+ /* Otherwise ensure that _rx_pkt definitely
192+ * does not hold any UdpRxPacket object anymore.
193+ */
194+ _rx_pkt.reset ();
195+ return 0 ;
196+ }
197+ }
198+
199+ int available ()
200+ {
201+ if (_rx_pkt)
202+ return _rx_pkt->available ();
203+ else
204+ return 0 ;
205+ }
206+
207+ int read ()
208+ {
209+ if (_rx_pkt)
210+ return _rx_pkt->read ();
211+ else
212+ return -1 ;
213+ }
214+
215+ int read (unsigned char * buffer, size_t len)
216+ {
217+ if (_rx_pkt)
218+ return _rx_pkt->read (buffer, len);
219+ else
220+ return -1 ;
221+ }
222+
223+ int read (char * buffer, size_t len)
224+ {
225+ if (_rx_pkt)
226+ return _rx_pkt->read (buffer, len);
227+ else
228+ return -1 ;
229+ }
230+
231+ int peek ()
232+ {
233+ if (_rx_pkt)
234+ return _rx_pkt->peek ();
235+ else
236+ return -1 ;
237+ }
238+
239+ void flush ()
240+ {
241+ /* Delete UdpRxPacket object held by _rx_pkt. */
242+ if (_rx_pkt)
243+ _rx_pkt.reset ();
244+ }
245+
246+ virtual IPAddress remoteIP () {
247+ if (_rx_pkt)
248+ return _rx_pkt->remoteIP ();
249+ else
250+ return IPAddress ();
251+ }
252+
253+ virtual uint16_t remotePort () {
254+ if (_rx_pkt)
255+ return _rx_pkt->remotePort ();
256+ else
257+ return 0 ;
258+ }
259+
260+ private:
261+
262+ /* UDP TRANSMISSION */
263+ IPAddress _send_to_ip;
264+ uint16_t _send_to_port;
265+ std::vector<uint8_t > _tx_data;
266+ int _rx_pkt_list_size = 10 ;
267+ /* UDP RECEPTION */
268+ class UdpRxPacket
269+ {
270+ private:
271+ IPAddress const _remote_ip;
272+ uint16_t const _remote_port;
273+ size_t const _rx_data_len;
274+ std::deque<uint8_t > _rx_data;
275+
276+ public:
277+ UdpRxPacket (
278+ IPAddress const remote_ip,
279+ uint16_t const remote_port,
280+ uint8_t const * p_data,
281+ size_t const data_len)
282+ : _remote_ip(remote_ip)
283+ , _remote_port(remote_port)
284+ , _rx_data_len(data_len)
285+ , _rx_data(p_data, p_data + data_len)
286+ {
287+ }
288+
289+ typedef std::shared_ptr<UdpRxPacket> SharedPtr;
290+
291+ IPAddress remoteIP () const { return _remote_ip; }
292+ uint16_t remotePort () const { return _remote_port; }
293+ size_t totalSize () const { return _rx_data_len; }
294+
295+ int available ()
296+ {
297+ return _rx_data.size ();
298+ }
299+
300+ int read ()
301+ {
302+ uint8_t const data = _rx_data.front ();
303+ _rx_data.pop_front ();
304+ return data;
305+ }
306+
307+ int read (unsigned char * buffer, size_t len)
308+ {
309+ size_t bytes_read = 0 ;
310+ for (; bytes_read < len && !_rx_data.empty (); bytes_read++)
311+ {
312+ buffer[bytes_read] = _rx_data.front ();
313+ _rx_data.pop_front ();
314+ }
315+ return bytes_read;
316+ }
317+
318+ int read (char * buffer, size_t len)
319+ {
320+ return read ((unsigned char *)buffer, len);
321+ }
322+
323+ int peek ()
324+ {
325+ return _rx_data.front ();
326+ }
327+ };
328+ std::list<UdpRxPacket::SharedPtr> _rx_pkt_list;
329+ UdpRxPacket::SharedPtr _rx_pkt;
330+ };
0 commit comments