virtual*/
| 206 | } |
| 207 | |
| 208 | /*virtual*/ void UDPInterface::loop() { |
| 209 | |
| 210 | if (_online) { |
| 211 | // Check for incoming packet |
| 212 | #ifdef ARDUINO |
| 213 | udp.parsePacket(); |
| 214 | size_t len = udp.read(_buffer.writable(Type::Reticulum::MTU), Type::Reticulum::MTU); |
| 215 | if (len > 0) { |
| 216 | _buffer.resize(len); |
| 217 | on_incoming(_buffer); |
| 218 | } |
| 219 | #else |
| 220 | // Drain all queued datagrams in one loop tick. The previous |
| 221 | // ioctl(FIONREAD)+read pattern returned a stale/zero `available` |
| 222 | // count on macOS for a UDP socket carrying back-to-back datagrams, |
| 223 | // which caused larger packets (~470B resource parts) to appear |
| 224 | // "lost" — they'd sit in the kernel queue while smaller follow-up |
| 225 | // packets were drained instead. recvfrom() with MSG_DONTWAIT reads |
| 226 | // exactly one datagram per call, sized to fit any link-layer MTU, |
| 227 | // and lets us loop until the queue is empty. |
| 228 | while (true) { |
| 229 | sockaddr_in src_addr{}; |
| 230 | socklen_t src_addr_len = sizeof(src_addr); |
| 231 | ssize_t len = recvfrom(_socket, |
| 232 | _buffer.writable(_HW_MTU), |
| 233 | _HW_MTU, |
| 234 | MSG_DONTWAIT, |
| 235 | (struct sockaddr*)&src_addr, |
| 236 | &src_addr_len); |
| 237 | if (len <= 0) { |
| 238 | break; |
| 239 | } |
| 240 | _buffer.resize(static_cast<size_t>(len)); |
| 241 | on_incoming(_buffer); |
| 242 | } |
| 243 | #endif |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | /*virtual*/ bool UDPInterface::send_outgoing(const Bytes& data) { |
| 248 | DEBUGF("%s.on_outgoing: data: %s", toString().c_str(), data.toHex().c_str()); |
no test coverage detected