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