18#include "lwip/priv/tcpip_priv.h"
45 struct udp_pcb *
out =
nullptr;
59static bool udp_pbuf_send(
struct udp_pcb *pcb,
const ip_addr_t *addr, u16_t port,
const uint8_t *data,
size_t len)
61 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)len, PBUF_RAM);
66 memcpy(p->payload, data, len);
67 err_t e = udp_sendto(pcb, p, addr, port);
75static void udp_trampoline(
void *arg,
struct udp_pcb *pcb,
struct pbuf *p,
const ip_addr_t *addr, u16_t port)
82 u16_t n = (p->tot_len <
sizeof(s_udp.
rx)) ? p->tot_len : (u16_t)
sizeof(s_udp.
rx);
83 pbuf_copy_partial(p, s_udp.
rx, n, 0);
110 struct tcpip_api_call_data
base;
124static inline void apply_udp_dscp(
struct udp_pcb *pcb)
126#if PC_ENABLE_DIFFSERV
127 uint8_t dscp = pc_diffserv_udp_dscp();
130 pcb->tos = pc_dscp_to_tos(dscp);
138static err_t udp_do(
struct tcpip_api_call_data *c)
147 struct udp_pcb *pcb = udp_new();
150 if (udp_bind(pcb, IP_ANY_TYPE, k->
port) == ERR_OK)
166 struct udp_pcb *pcb = udp_new();
175 ip_set_option(pcb, SOF_REUSEADDR);
176 if (udp_bind(pcb, IP4_ADDR_ANY, k->
port) == ERR_OK &&
177 igmp_joingroup(IP4_ADDR_ANY4, ip_2_ip4(&k->
addr)) == ERR_OK)
196 igmp_leavegroup(IP4_ADDR_ANY4, ip_2_ip4(&l->
group));
213 s_udp.
out = udp_new();
217 apply_udp_dscp(s_udp.
out);
239 memset(&k, 0,
sizeof(k));
243 tcpip_api_call(udp_do, &k.
base);
263 if (!ipaddr_aton(group_ip, &group) || !IP_IS_V4(&group))
268 if (!ip4_addr_ismulticast(ip_2_ip4(&group)))
285 memset(&k, 0,
sizeof(k));
290 tcpip_api_call(udp_do, &k.
base);
320 memset(&k, 0,
sizeof(k));
323 tcpip_api_call(udp_do, &k.
base);
338 if (!peer || !peer->
pcb || !peer->
addr || !data || len == 0)
344 return udp_pbuf_send(peer->
pcb, peer->
addr, peer->
port, data, len);
347 memset(&k, 0,
sizeof(k));
354 tcpip_api_call(udp_do, &k.
base);
358bool pc_udp_sendto(
const char *dst_ip, uint16_t dst_port,
const uint8_t *data,
size_t len)
360 if (!dst_ip || !data || len == 0)
365 if (!ipaddr_aton(dst_ip, &dst))
373 s_udp.
out = udp_new();
379 apply_udp_dscp(s_udp.
out);
380 return udp_pbuf_send(s_udp.
out, &dst, dst_port, data, len);
383 memset(&k, 0,
sizeof(k));
389 tcpip_api_call(udp_do, &k.
base);
395 if (!peer || !peer->
addr || !ip_out || ip_cap < 8)
399 ipaddr_ntoa_r(peer->
addr, ip_out, (
int)ip_cap);
402 *port_out = peer->
port;
410 if (!dst_ip || !data || len == 0)
415 if (!ipaddr_aton(dst_ip, &dst))
419 struct udp_pcb *pcb =
nullptr;
434 return udp_pbuf_send(pcb, &dst, dst_port, data, len);
437 memset(&k, 0,
sizeof(k));
444 tcpip_api_call(udp_do, &k.
base);
464struct HostUdpListener
477 uint8_t cap_buf[2048];
479 bool listener_sendto_ok;
481HostUdpCtx s_udp = {{},
false, {}, 0,
true};
484bool host_capture(
const uint8_t *data,
size_t len)
486 if (s_udp.cap_on && data && len && len <=
sizeof(s_udp.cap_buf))
488 memcpy(s_udp.cap_buf, data, len);
499 HostUdpListener *slot =
nullptr;
502 if (s_udp.lst[i].used && s_udp.lst[i].port == port)
504 slot = &s_udp.lst[i];
509 if (!s_udp.lst[i].used)
511 slot = &s_udp.lst[i];
516 slot = &s_udp.lst[0];
519 slot->handler = handler;
530static bool parse_mcast_group(
const char *ip,
size_t *len_out)
539 bool have_digit =
false;
543 if (*p >=
'0' && *p <=
'9')
545 octet = octet * 10 + (uint32_t)(*p -
'0');
552 else if (*p ==
'.' || *p ==
'\0')
554 if (!have_digit || count == 4)
575 if (count != 4 || first < 224 || first > 239)
579 *len_out = (size_t)(p - ip);
586 if (!parse_mcast_group(group_ip, &glen))
596 if (glen >=
sizeof(s_udp.lst[0].group))
613 if (s_udp.lst[i].used && s_udp.lst[i].port == port)
615 memcpy(s_udp.lst[i].group, group_ip, glen + 1);
616 s_udp.lst[i].mcast =
true;
627 if (s_udp.lst[i].used && s_udp.lst[i].mcast && s_udp.lst[i].port == port)
636const char *pc_udp_joined_group(uint16_t port)
640 if (s_udp.lst[i].used && s_udp.lst[i].mcast && s_udp.lst[i].port == port)
642 return s_udp.lst[i].group;
648void pc_udp_inject(uint16_t listen_port,
const char *src_ip, uint16_t src_port,
const uint8_t *data,
size_t len)
652 if (s_udp.lst[i].used && s_udp.lst[i].port == listen_port && s_udp.lst[i].handler)
655 strncpy(peer.ip, src_ip ? src_ip :
"", sizeof(peer.ip) - 1);
656 peer.ip[
sizeof(peer.ip) - 1] =
'\0';
657 peer.
port = src_port;
658 s_udp.lst[i].handler(data, len, &peer, s_udp.lst[i].ctx);
664void pc_udp_set_listener_sendto_result(
bool ok)
666 s_udp.listener_sendto_ok = ok;
669void pc_udp_reset_listeners()
675 s_udp.listener_sendto_ok =
true;
681 return host_capture(data, len);
684void pc_udp_capture_enable()
689void pc_udp_capture_reset()
693const uint8_t *pc_udp_captured()
695 return s_udp.cap_len ? s_udp.cap_buf :
nullptr;
697size_t pc_udp_captured_len()
699 return s_udp.cap_len;
702bool pc_udp_sendto(
const char *dst_ip, uint16_t dst_port,
const uint8_t *data,
size_t len)
706 return host_capture(data, len);
715 if (ip_out && ip_cap)
717 strncpy(ip_out, peer->ip, ip_cap - 1);
718 ip_out[ip_cap - 1] =
'\0';
722 *port_out = peer->
port;
727bool pc_udp_listener_sendto(uint16_t listen_port,
const char *dst_ip, uint16_t dst_port,
const uint8_t *data,
733 if (!s_udp.listener_sendto_ok)
737 host_capture(data, len);
Layer 4 (Transport) - DiffServ QoS marking (RFC 2474) for outbound traffic.
#define PC_UDP_RX_BUF_SIZE
Shared receive-scratch size for the transport-layer UDP service.
#define PC_MAX_UDP_LISTENERS
Maximum simultaneously bound UDP ports (transport-layer UDP service).
UdpListener listeners[PC_MAX_UDP_LISTENERS]
uint8_t rx[PC_UDP_RX_BUF_SIZE]
volatile bool in_tcpip_thread
struct tcpip_api_call_data base
bool pc_udp_sendto(const char *dst_ip, uint16_t dst_port, const uint8_t *data, size_t len)
Send a UDP datagram to an arbitrary destination (outbound client).
bool pc_udp_listener_sendto(uint16_t listen_port, const char *dst_ip, uint16_t dst_port, const uint8_t *data, size_t len)
Send a datagram from the listener bound on listen_port to an address.
bool pc_udp_listen(uint16_t port, pc_udp_handler handler, void *ctx)
Bind a UDP port and route incoming datagrams to handler.
bool pc_udp_send(const struct pc_udp_peer *peer, const uint8_t *data, size_t len)
Send a datagram back to the peer captured during the handler call.
bool pc_udp_listen_multicast(const char *group_ip, uint16_t port, pc_udp_handler handler, void *ctx)
Bind a UDP port, join an IPv4 multicast group, and route group datagrams to handler.
bool pc_udp_leave_multicast(uint16_t port)
Leave the multicast group joined on port and release its listener slot.
bool pc_udp_peer_addr(const struct pc_udp_peer *peer, char *ip_out, size_t ip_cap, uint16_t *port_out)
Copy a received peer's source IPv4 address (dotted-quad) and port out.
Layer 4 (Transport) - connectionless UDP datagram service.
void(* pc_udp_handler)(const uint8_t *data, size_t len, const struct pc_udp_peer *peer, void *ctx)
Datagram handler invoked for each received UDP packet.