@@ -32,7 +32,8 @@ void esp_schedule();
32
32
33
33
#include < AddrList.h>
34
34
35
- #define GET_UDP_HDR (pb ) (reinterpret_cast <udp_hdr*>(((uint8_t *)((pb)->payload)) - UDP_HLEN))
35
+ #define PBUF_ALIGNER_ADJUST 4
36
+ #define PBUF_ALIGNER (x ) ((void *)((((intptr_t )(x))+3 )&~3 ))
36
37
37
38
class UdpContext
38
39
{
@@ -207,21 +208,17 @@ class UdpContext
207
208
208
209
CONST IPAddress& getRemoteAddress () CONST
209
210
{
210
- return _src_addr ;
211
+ return _currentAddr. srcaddr ;
211
212
}
212
213
213
214
uint16_t getRemotePort () const
214
215
{
215
- if (!_rx_buf)
216
- return 0 ;
217
-
218
- udp_hdr* udphdr = GET_UDP_HDR (_rx_buf);
219
- return lwip_ntohs (udphdr->src );
216
+ return _currentAddr.srcport ;
220
217
}
221
218
222
219
const IPAddress& getDestAddress () const
223
220
{
224
- return _dst_addr ;
221
+ return _currentAddr. dstaddr ;
225
222
}
226
223
227
224
uint16_t getLocalPort () const
@@ -235,23 +232,41 @@ class UdpContext
235
232
{
236
233
if (!_rx_buf)
237
234
return false ;
238
-
239
235
if (!_first_buf_taken)
240
236
{
241
237
_first_buf_taken = true ;
242
238
return true ;
243
239
}
244
240
245
- auto head = _rx_buf;
241
+ auto deleteme = _rx_buf;
246
242
_rx_buf = _rx_buf->next ;
247
- _rx_buf_offset = 0 ;
248
243
249
244
if (_rx_buf)
250
245
{
246
+ // we have interleaved informations on addresses within reception pbuf chain:
247
+ // before: (data-pbuf) -> (data-pbuf) -> (data-pbuf) -> ... in the receiving order
248
+ // now: (address-info-pbuf -> data-pbuf) -> (address-info-pbuf -> data-pbuf) -> ...
249
+
250
+ // so the first rx_buf contains an address helper,
251
+ // copy it to "current address"
252
+ auto helper = (AddrHelper*)PBUF_ALIGNER (_rx_buf->payload );
253
+ _currentAddr = *helper;
254
+
255
+ // destroy the helper in the about-to-be-released pbuf
256
+ helper->~AddrHelper ();
257
+
258
+ // forward in rx_buf list, next one is effective data
259
+ // current (not ref'ed) one will be pbuf_free'd with deleteme
260
+ _rx_buf = _rx_buf->next ;
261
+
262
+ // this rx_buf is not nullptr by construction,
263
+ // ref'ing it to prevent release from the below pbuf_free(deleteme)
251
264
pbuf_ref (_rx_buf);
252
265
}
253
- pbuf_free (head);
254
- return _rx_buf != 0 ;
266
+ pbuf_free (deleteme);
267
+
268
+ _rx_buf_offset = 0 ;
269
+ return _rx_buf != nullptr ;
255
270
}
256
271
257
272
int read ()
@@ -420,54 +435,74 @@ class UdpContext
420
435
}
421
436
422
437
void _recv (udp_pcb *upcb, pbuf *pb,
423
- const ip_addr_t *addr , u16_t port )
438
+ const ip_addr_t *srcaddr , u16_t srcport )
424
439
{
425
440
(void ) upcb;
426
- (void ) addr;
427
- (void ) port;
441
+
442
+ #if LWIP_VERSION_MAJOR == 1
443
+ #define TEMPDSTADDR (¤t_iphdr_dest)
444
+ #else
445
+ #define TEMPDSTADDR (ip_current_dest_addr())
446
+ #endif
447
+
448
+ // chain this helper pbuf first
428
449
if (_rx_buf)
429
450
{
430
451
// there is some unread data
431
- // chain the new pbuf to the existing one
452
+ // chain pbuf
453
+
454
+ // Addresses/ports are stored from this callback because lwIP's
455
+ // macro are valid only now.
456
+ //
457
+ // When peeking data from before payload start (like it was done
458
+ // before IPv6), there's no easy way to safely guess whether
459
+ // packet is from v4 or v6.
460
+ //
461
+ // Now storing data in an intermediate chained pbuf containing
462
+ // AddrHelper
463
+
464
+ // allocate new pbuf to store addresses/ports
465
+ pbuf* pb_helper = pbuf_alloc (PBUF_RAW, sizeof (AddrHelper) + PBUF_ALIGNER_ADJUST, PBUF_RAM);
466
+ if (!pb_helper)
467
+ {
468
+ // memory issue - discard received data
469
+ pbuf_free (pb);
470
+ return ;
471
+ }
472
+ // construct in place
473
+ new (PBUF_ALIGNER (pb_helper->payload )) AddrHelper (srcaddr, TEMPDSTADDR, srcport);
474
+ // chain it
475
+ pbuf_cat (_rx_buf, pb_helper);
476
+
477
+ // now chain the new data pbuf
432
478
DEBUGV (" :urch %d, %d\r\n " , _rx_buf->tot_len , pb->tot_len );
433
479
pbuf_cat (_rx_buf, pb);
434
480
}
435
481
else
436
482
{
483
+ _currentAddr.srcaddr = srcaddr;
484
+ _currentAddr.dstaddr = TEMPDSTADDR;
485
+ _currentAddr.srcport = srcport;
486
+
437
487
DEBUGV (" :urn %d\r\n " , pb->tot_len );
438
488
_first_buf_taken = false ;
439
489
_rx_buf = pb;
440
490
_rx_buf_offset = 0 ;
441
491
}
442
492
443
- // --> Arduino's UDP is a stream but UDP is not <--
444
- // When IPv6 is enabled, we store addresses from here
445
- // because lwIP's macro are valid only in this callback
446
- // (there's no easy way to safely guess whether packet
447
- // is from v4 or v6 when we have only access to payload)
448
- // Because of this stream-ed way this is inacurate when
449
- // user does not swallow data quickly enough (the former
450
- // IPv4-only way suffers from the exact same issue.
451
-
452
- #if LWIP_VERSION_MAJOR == 1
453
- _src_addr = current_iphdr_src;
454
- _dst_addr = current_iphdr_dest;
455
- #else
456
- _src_addr = ip_data.current_iphdr_src ;
457
- _dst_addr = ip_data.current_iphdr_dest ;
458
- #endif
459
-
460
493
if (_on_rx) {
461
494
_on_rx ();
462
495
}
463
- }
464
496
497
+ #undef TEMPDSTADDR
498
+
499
+ }
465
500
466
501
static void _s_recv (void *arg,
467
502
udp_pcb *upcb, pbuf *p,
468
- CONST ip_addr_t *addr , u16_t port )
503
+ CONST ip_addr_t *srcaddr , u16_t srcport )
469
504
{
470
- reinterpret_cast <UdpContext*>(arg)->_recv (upcb, p, addr, port );
505
+ reinterpret_cast <UdpContext*>(arg)->_recv (upcb, p, srcaddr, srcport );
471
506
}
472
507
473
508
private:
@@ -483,7 +518,16 @@ class UdpContext
483
518
#ifdef LWIP_MAYBE_XCC
484
519
uint16_t _mcast_ttl;
485
520
#endif
486
- IPAddress _src_addr, _dst_addr;
521
+ struct AddrHelper
522
+ {
523
+ IPAddress srcaddr, dstaddr;
524
+ int16_t srcport;
525
+
526
+ AddrHelper () { }
527
+ AddrHelper (const ip_addr_t * src, const ip_addr_t * dst, uint16_t srcport):
528
+ srcaddr (src), dstaddr(dst), srcport(srcport) { }
529
+ };
530
+ AddrHelper _currentAddr;
487
531
};
488
532
489
533
0 commit comments