@@ -32,7 +32,8 @@ void esp_schedule();
3232
3333#include < AddrList.h>
3434
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 ))
3637
3738class UdpContext
3839{
@@ -207,21 +208,17 @@ class UdpContext
207208
208209 CONST IPAddress& getRemoteAddress () CONST
209210 {
210- return _src_addr ;
211+ return _currentAddr. srcaddr ;
211212 }
212213
213214 uint16_t getRemotePort () const
214215 {
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 ;
220217 }
221218
222219 const IPAddress& getDestAddress () const
223220 {
224- return _dst_addr ;
221+ return _currentAddr. dstaddr ;
225222 }
226223
227224 uint16_t getLocalPort () const
@@ -235,23 +232,41 @@ class UdpContext
235232 {
236233 if (!_rx_buf)
237234 return false ;
238-
239235 if (!_first_buf_taken)
240236 {
241237 _first_buf_taken = true ;
242238 return true ;
243239 }
244240
245- auto head = _rx_buf;
241+ auto deleteme = _rx_buf;
246242 _rx_buf = _rx_buf->next ;
247- _rx_buf_offset = 0 ;
248243
249244 if (_rx_buf)
250245 {
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)
251264 pbuf_ref (_rx_buf);
252265 }
253- pbuf_free (head);
254- return _rx_buf != 0 ;
266+ pbuf_free (deleteme);
267+
268+ _rx_buf_offset = 0 ;
269+ return _rx_buf != nullptr ;
255270 }
256271
257272 int read ()
@@ -420,54 +435,74 @@ class UdpContext
420435 }
421436
422437 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 )
424439 {
425440 (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
428449 if (_rx_buf)
429450 {
430451 // 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
432478 DEBUGV (" :urch %d, %d\r\n " , _rx_buf->tot_len , pb->tot_len );
433479 pbuf_cat (_rx_buf, pb);
434480 }
435481 else
436482 {
483+ _currentAddr.srcaddr = srcaddr;
484+ _currentAddr.dstaddr = TEMPDSTADDR;
485+ _currentAddr.srcport = srcport;
486+
437487 DEBUGV (" :urn %d\r\n " , pb->tot_len );
438488 _first_buf_taken = false ;
439489 _rx_buf = pb;
440490 _rx_buf_offset = 0 ;
441491 }
442492
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-
460493 if (_on_rx) {
461494 _on_rx ();
462495 }
463- }
464496
497+ #undef TEMPDSTADDR
498+
499+ }
465500
466501 static void _s_recv (void *arg,
467502 udp_pcb *upcb, pbuf *p,
468- CONST ip_addr_t *addr , u16_t port )
503+ CONST ip_addr_t *srcaddr , u16_t srcport )
469504 {
470- reinterpret_cast <UdpContext*>(arg)->_recv (upcb, p, addr, port );
505+ reinterpret_cast <UdpContext*>(arg)->_recv (upcb, p, srcaddr, srcport );
471506 }
472507
473508private:
@@ -483,7 +518,16 @@ class UdpContext
483518#ifdef LWIP_MAYBE_XCC
484519 uint16_t _mcast_ttl;
485520#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;
487531};
488532
489533
0 commit comments