NetBurner 3.5.6
PDF Version
UDPPacket Class Reference

UDP Packet Class - Complete UDP packet management. More...

#include <udp.h>

Public Member Functions

 UDPPacket (OS_FIFO *pFifo, TickTimeout timeout)
 Create UDP packet from FIFO with timeout.
 
 UDPPacket (int sock)
 Create UDP packet from socket (blocks until data available)
 
 UDPPacket (PoolPtr p)
 Create from raw pool buffer (ADVANCED - rarely needed)
 
 UDPPacket (UDPPacket &pkt)
 Move constructor - transfers ownership.
 
 UDPPacket (bool bIsIpv6=false)
 Construct a new UDP packet object.
 
 ~UDPPacket ()
 Destructor - automatically frees pool buffer.
 
bool Receive (OS_FIFO *pFifo, uint32_t wait_ticks)
 Reuse packet object for multiple receives (efficiency optimization)
 
void SetSourcePort (uint16_t port)
 Set source port (0=auto-assign ephemeral port, 1024-65535=specific port)
 
uint16_t GetSourcePort (void) const
 Get source port from received packet or previously set value.
 
MACADR GetMacSource ()
 Get sender's MAC address (link-layer identification)
 
IPADDR GetSourceAddress (void)
 Get source IP address of the packet.
 
IPADDR GetDestinationAddress (void)
 Get destination IP address of the packet.
 
bool bIsIPV6 () const
 Check if packet uses IPv6 addressing.
 
void SetDestinationPort (uint16_t port)
 Set destination port (standard services: 53=DNS, 80=HTTP, 123=NTP, 161=SNMP)
 
uint16_t GetDestinationPort (void) const
 Get destination port (for received packets: local port that received it)
 
uint16_t GetPacketId (void)
 Get IP packet ID (used for fragment reassembly and packet tracking)
 
void SetDSCP (uint8_t dscp)
 Set DSCP for QoS (0=best effort, 46=VoIP/EF, 34=video/AF41, 8=bulk/CS1)
 
uint8_t GetDSCP (void) const
 Get DSCP value (0-63)
 
puint8_t GetDataBuffer (bool bReAllocateIfNeeded=false)
 Get data buffer pointer for reading or writing.
 
void SetDataSize (uint16_t numBytes)
 Set data size (REQUIRED after GetDataBuffer() writes)
 
uint16_t GetDataSize (void) const
 Get current data size in bytes.
 
void AddData (puint8_t pData, uint16_t len)
 Add binary data (auto-updates size - no SetDataSize() needed)
 
void AddData (PCSTR pData)
 Add null-terminated string (includes NULL in packet)
 
void AddDataWord (uint16_t w)
 Add 16-bit value.
 
void AddDataByte (uint8_t b)
 Add 8-bit value.
 
BOOL Validate (void)
 Validate received packet (checks checksum and data presence)
 
void ResetData (void)
 Reset data size to 0 (clears packet)
 
void SendAndKeep (const IPADDR &to, uint8_t ttl=0)
 Send copy, keep original (for sending to multiple destinations)
 
void Send (const IPADDR &to, uint8_t ttl=0)
 Send and free buffer (recommended - most efficient)
 
void SendAndKeepViaInterfaceNum (const IPADDR &to, int interface, uint8_t ttl=0)
 Send copy via specific interface, keep original.
 
void SendViaInterfaceNum (const IPADDR &to, int interface, uint8_t ttl=0)
 Send via specific interface and free buffer.
 
void SendAndKeepViaIfAddr (const IPADDR &to, const IPADDR &from_ip, uint8_t ttl=0)
 Send a packet and retain a copy via a specific interface address.
 
void SendViaIfAddr (const IPADDR &to, const IPADDR &from_ip, uint8_t ttl=0)
 Send a packet via a specific interface address.
 

Detailed Description

UDP Packet Class - Complete UDP packet management.

Provides comprehensive UDP packet handling with automatic memory management, flexible data insertion methods, and advanced sending options.

Transmission Patterns

Method 1: sprintf with GetDataBuffer() - Best for formatted text

pkt.SetSourcePort(123);
uint16_t len = sprintf(pkt.GetDataBuffer(), "Temp: %d", temp);
pkt.SetDataSize(len); // IMPORTANT: Must set size!
pkt.Send(destIP);
UDP Packet Class - Complete UDP packet management.
Definition udp.h:602
void Send(const IPADDR &to, uint8_t ttl=0)
Send and free buffer (recommended - most efficient)
Definition udp.h:3391
void SetDestinationPort(uint16_t port)
Set destination port (standard services: 53=DNS, 80=HTTP, 123=NTP, 161=SNMP)
void SetSourcePort(uint16_t port)
Set source port (0=auto-assign ephemeral port, 1024-65535=specific port)
void SetDataSize(uint16_t numBytes)
Set data size (REQUIRED after GetDataBuffer() writes)
puint8_t GetDataBuffer(bool bReAllocateIfNeeded=false)
Get data buffer pointer for reading or writing.

Method 2: AddData() - Best for binary/incremental data

pkt.SetSourcePort(123);
pkt.AddData(header, sizeof(header));
pkt.AddDataWord(sensor);
pkt.Send(destIP);
void AddData(puint8_t pData, uint16_t len)
Add binary data (auto-updates size - no SetDataSize() needed)
void AddDataWord(uint16_t w)
Add 16-bit value.

Reception Pattern

OS_FIFO udpFifo;
OSFifoInit(&udpFifo);
RegisterUDPFifo(PORT, &udpFifo);
while (1) {
UDPPacket pkt(&udpFifo, TICKS_PER_SECOND * 5);
if (pkt.Validate()) {
// Process pkt.GetDataBuffer() and pkt.GetDataSize()
}
}
BOOL Validate(void)
Validate received packet (checks checksum and data presence)
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
bool RegisterUDPFifo(uint16_t listenPort, OS_FIFO *pFifo)
Register FIFO to receive UDP packets on specified port.
See also
RegisterUDPFifo(), OS_FIFO

Constructor & Destructor Documentation

◆ UDPPacket() [1/5]

UDPPacket::UDPPacket ( OS_FIFO * pFifo,
TickTimeout timeout )

Create UDP packet from FIFO with timeout.

Constructs a UDPPacket by receiving data from a registered FIFO queue with a specified timeout. This constructor blocks until either a packet arrives or the timeout expires. The packet may be invalid even if the constructor returns, so ALWAYS call Validate() immediately after construction.

Parameters
pFifoPointer to OS_FIFO queue registered with RegisterUDPFifo()
timeoutTimeout duration in system ticks:
  • 0 = Non-blocking (return immediately if no packet)
  • TICKS_PER_SECOND = 1 second timeout
  • TICKS_PER_SECOND * N = N second timeout
  • 0xFFFFFFFF = Wait forever (blocking)
Note
CRITICAL: ALWAYS call Validate() after construction before using packet data
Timeout expiration does not guarantee an invalid packet - always check with Validate()
The FIFO must be created with OSFifoInit() and registered with RegisterUDPFifo()
This constructor blocks the calling task until packet arrives or timeout
For non-blocking behavior, use timeout=0 and check Validate()
Warning
NEVER access packet data without calling Validate() first!
A timeout does NOT mean the packet is invalid - must still validate
The FIFO must be registered before using this constructor
Constructor vs Receive() Method:
This constructor is equivalent to:
pkt.Receive(pFifo, timeout);
bool Receive(OS_FIFO *pFifo, uint32_t wait_ticks)
Reuse packet object for multiple receives (efficiency optimization)
Definition udp.h:2049
However, using the Receive() method in a loop is more efficient than constructing new packets repeatedly.
FIFO Setup Requirements:
Before using this constructor:
OS_FIFO udpFifo;
OSFifoInit(&udpFifo); // Initialize FIFO
RegisterUDPFifo(5000, &udpFifo); // Register on port 5000

Expand for Example Usage

Examples

Example Usage - Basic Receive with Timeout:
OS_FIFO udpFifo;
OSFifoInit(&udpFifo);
RegisterUDPFifo(5000, &udpFifo);
// Receive with 5 second timeout
UDPPacket pkt(&udpFifo, TICKS_PER_SECOND * 5);
if (pkt.Validate()) {
printf("Got %d bytes from %s:%d\r\n",
pkt.GetDataSize(),
pkt.GetSourceAddress().ToString(),
pkt.GetSourcePort());
ProcessPacket(pkt);
} else {
printf("No valid packet (timeout or corrupt)\r\n");
}
Example Usage - Non-Blocking Check:
// Check for packet without blocking
UDPPacket pkt(&udpFifo, 0); // timeout=0, immediate return
if (pkt.Validate()) {
printf("Packet available!\r\n");
ProcessPacket(pkt);
} else {
// No packet available right now - continue other work
DoOtherWork();
}
Example Usage - Server Loop (INEFFICIENT):
// INEFFICIENT - Creates new packet each iteration
while (running) {
UDPPacket pkt(&udpFifo, TICKS_PER_SECOND); // Allocation overhead!
if (pkt.Validate()) {
ProcessPacket(pkt);
}
}
// EFFICIENT - Reuse same packet object
while (running) {
if (pkt.Receive(&udpFifo, TICKS_PER_SECOND)) { // Better approach
if (pkt.Validate()) {
ProcessPacket(pkt);
}
}
}
Example Usage - Heartbeat Monitoring:
OS_FIFO heartbeatFifo;
OSFifoInit(&heartbeatFifo);
RegisterUDPFifo(9000, &heartbeatFifo);
// Wait for heartbeat with 10 second timeout
UDPPacket hb(&heartbeatFifo, TICKS_PER_SECOND * 10);
if (hb.Validate()) {
printf("Heartbeat received - connection alive\r\n");
lastHeartbeat = Secs;
} else {
printf("Heartbeat timeout - connection may be lost\r\n");
HandleConnectionLost();
}
Example Usage - Request with Timeout:
// Send request
UDPPacket request;
request.SetDestinationPort(8080);
request.AddData("GET_STATUS", 10);
request.Send(serverIP);
// Wait for response with 3 second timeout
OS_FIFO responseFifo;
OSFifoInit(&responseFifo);
RegisterUDPFifo(0, &responseFifo); // Listen on any available port
UDPPacket response(&responseFifo, TICKS_PER_SECOND * 3);
if (response.Validate()) {
printf("Response received within timeout\r\n");
ProcessResponse(response);
} else {
printf("Request timeout - server not responding\r\n");
HandleTimeout();
}

When to Use This Constructor:
Scenario Use This Constructor? Better Alternative
One-time receive Yes N/A
Loop with many receives No Use Receive() method
Quick test/debug Yes Convenient for testing
Performance critical No Reuse packet object
Multiple ports Maybe Consider Receive()
Timeout Behavior:
  • Constructor returns after timeout expires, even without packet
  • Validate() will return false if no packet received
  • Validate() may return false even if packet received (corrupted)
  • Always check Validate() - never assume timeout means invalid
See also
Validate(), Receive(), RegisterUDPFifo(), OSFifoInit(), UDPPacket()

◆ UDPPacket() [2/5]

UDPPacket::UDPPacket ( int sock)

Create UDP packet from socket (blocks until data available)

Constructs a UDPPacket by receiving data from a UDP socket. This constructor blocks until data is available on the socket. Best practice: Use after select() or poll() to ensure data is ready before calling this constructor to avoid unexpected blocking.

Parameters
sockUDP socket descriptor from CreateRxUdpSocket() or CreateRxTxUdpSocket()
Note
CRITICAL: This constructor BLOCKS if no data is available
Use select() or poll() first to check if data is ready
Always call Validate() after construction to verify packet integrity
The socket must be a valid UDP socket (SOCK_DGRAM)
For non-blocking behavior, set socket to non-blocking mode first
Warning
Will BLOCK indefinitely if no data arrives and socket is blocking
Always use with select()/poll() or set socket to non-blocking mode
The socket must remain valid - don't close it while packet exists
Recommended Pattern:
Always use select() before this constructor to avoid blocking:
  1. Use select() to check if data is ready
  2. If data ready, construct UDPPacket (won't block)
  3. Call Validate() to verify packet
  4. Process packet data
Socket Creation:
Before using this constructor, create a UDP socket:
// Receive-only socket
int sock = CreateRxUdpSocket(1234); // Listen on port 1234
// Or receive/transmit socket
int sock = CreateRxTxUdpSocket(1234); // Port 1234
int CreateRxUdpSocket(uint16_t listening_port)
Create receive-only UDP socket bound to specified port.
int CreateRxTxUdpSocket(const IPADDR &send_to_addr, uint16_t send_to_remote_port, uint16_t local_port)
Create bidirectional UDP socket for both sending and receiving.
Definition udp.h:5748

Expand for Example Usage

Examples

Example Usage - Basic with select():
int sock = CreateRxUdpSocket(1234);
// Setup select() to wait for data
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
if (select(sock + 1, &readfds, NULL, NULL, NULL) > 0) {
// Data is ready - constructor won't block
UDPPacket pkt(sock);
if (pkt.Validate()) {
printf("Received packet from %s:%u\r\n",
pkt.GetSourceAddress().ToString(),
pkt.GetSourcePort());
ProcessPacket(pkt);
}
}
void FD_SET(int fd, fd_set *pfds)
A fd_set (file descriptor set) holds a set of file descriptors (fds). This function sets or adds a sp...
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, unsigned long timeout)
Wait for events to occur on one or more I/O resources associated with a set of file descriptors (fds)...
void FD_ZERO(fd_set *pfds)
Clear (set to 0) a fd_set (file descriptor set) so no file descriptors (fds) are selected.
Example Usage - With Timeout:
int sock = CreateRxUdpSocket(5000);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
// Wait up to 5 seconds for data
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
int result = select(sock + 1, &readfds, NULL, NULL, &tv);
if (result > 0) {
UDPPacket pkt(sock); // Data ready - won't block
if (pkt.Validate()) {
ProcessPacket(pkt);
}
} else if (result == 0) {
printf("Timeout - no data received\r\n");
} else {
printf("Select error\r\n");
}
Example Usage - Multiple Sockets:
int controlSock = CreateRxUdpSocket(5000);
int dataSock = CreateRxUdpSocket(5001);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(controlSock, &readfds);
FD_SET(dataSock, &readfds);
int maxfd = (controlSock > dataSock) ? controlSock : dataSock;
if (select(maxfd + 1, &readfds, NULL, NULL, NULL) > 0) {
if (FD_ISSET(controlSock, &readfds)) {
UDPPacket ctrlPkt(controlSock);
if (ctrlPkt.Validate()) {
ProcessControlPacket(ctrlPkt);
}
}
if (FD_ISSET(dataSock, &readfds)) {
UDPPacket dataPkt(dataSock);
if (dataPkt.Validate()) {
ProcessDataPacket(dataPkt);
}
}
}
int FD_ISSET(int fd, fd_set *pfds)
A fd_set (file descriptor set) holds a set of file descriptors (fds). This function checks whether or...
Example Usage - Server Loop:
int sock = CreateRxUdpSocket(8080);
while (running) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
struct timeval tv = {1, 0}; // 1 second timeout
if (select(sock + 1, &fds, NULL, NULL, &tv) > 0) {
UDPPacket pkt(sock);
if (pkt.Validate()) {
IPADDR clientAddr = pkt.GetSourceAddress();
uint16_t clientPort = pkt.GetSourcePort();
printf("Request from %s:%u\r\n",
clientAddr.ToString(), clientPort);
// Send response
UDPPacket response;
response.SetDestinationPort(clientPort);
response.AddData("ACK", 3);
response.Send(clientAddr);
}
}
// Timeout - check for shutdown, do housekeeping, etc.
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition ipv6_addr.h:41
Example Usage - Non-Blocking Socket:
int sock = CreateRxUdpSocket(6000);
// Set socket to non-blocking mode
int flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
// Now constructor won't block - returns immediately
UDPPacket pkt(sock);
if (pkt.Validate()) {
printf("Packet received\r\n");
ProcessPacket(pkt);
} else {
// Either no data or invalid packet
printf("No valid packet available\r\n");
}

Socket vs FIFO Approach:
Approach Pros Cons
Socket (this) Works with select(), standard BSD sockets Requires select() setup
FIFO (other constructors) Simple, RTOS-native, efficient NetBurner-specific API
When to Use Sockets:
  • Integrating with select()-based event loops
  • Porting BSD socket code to NetBurner
  • Multiplexing multiple UDP ports
  • Need timeout with standard timeval
  • Compatibility with POSIX socket APIs
When to Use FIFOs:
  • Pure RTOS design (no select needed)
  • Higher performance (fewer layers)
  • NetBurner-native applications
  • Integration with other OS_FIFO queues
Common Mistakes:
// WRONG - Will block forever if no data!
int sock = CreateRxUdpSocket(1234);
UDPPacket pkt(sock); // BLOCKS until packet arrives
// CORRECT - Check with select() first
int sock = CreateRxUdpSocket(1234);
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
if (select(sock + 1, &fds, NULL, NULL, NULL) > 0) {
UDPPacket pkt(sock); // Won't block - data ready
}
// ALSO CORRECT - Non-blocking socket
int sock = CreateRxUdpSocket(1234);
fcntl(sock, F_SETFL, O_NONBLOCK);
UDPPacket pkt(sock); // Returns immediately
See also
Validate(), CreateRxUdpSocket(), CreateRxTxUdpSocket(), select(), UDPPacket(OS_FIFO*, uint32_t)

◆ UDPPacket() [3/5]

UDPPacket::UDPPacket ( PoolPtr p)

Create from raw pool buffer (ADVANCED - rarely needed)

Constructs a UDPPacket by wrapping an existing pool buffer pointer. This is an advanced constructor for custom protocol implementations that work directly with the NetBurner pool buffer system. The UDPPacket takes ownership of the buffer and will automatically free it when destroyed.

Parameters
pPool buffer pointer (PoolPtr) containing packet data
Warning
DANGEROUS - Incorrect use causes memory corruption, double-frees, or crashes
Only use if you fully understand the NetBurner pool buffer allocation system
The pool buffer must be properly allocated and formatted
UDPPacket assumes FULL OWNERSHIP - do not free the buffer elsewhere
After passing to UDPPacket, the original PoolPtr should not be used
Note
This constructor is for EXPERT USE ONLY
Most applications should use UDPPacket() or UDPPacket(bool) instead
Required for custom protocol stacks or low-level network code
The buffer must contain valid UDP/IP headers in the correct format
When This Constructor Is Needed:
  • Implementing custom network protocols below UDP level
  • Interfacing with raw network drivers
  • Zero-copy optimizations in performance-critical code
  • Custom packet inspection/modification tools
  • Working with network hardware at buffer level
Prerequisites:
Before using this constructor, you must understand:
  • NetBurner pool buffer allocation (GetBuffer/FreeBuffer)
  • UDP/IP packet header structures
  • Buffer ownership and lifecycle management
  • Memory alignment requirements
  • Reference counting semantics
Buffer Ownership Rules:
PoolPtr buf = AllocatePoolBuffer(); // You own buffer
// ... format buffer with UDP/IP headers ...
UDPPacket pkt(buf); // UDPPacket now owns buffer
// DO NOT use 'buf' anymore - ownership transferred!
// DO NOT call FreeBuffer(buf) - UDPPacket will do it
// When pkt goes out of scope or is destroyed, buffer is freed
Main buffer structure for network and serial communication.
Definition buffers.h:90

Expand for Example Usage

Examples

Example Usage - Custom Protocol (Expert Level):
// ADVANCED EXAMPLE - Only for experts!
PoolPtr CreateCustomUDPPacket(const uint8_t* data, uint16_t len) {
// Allocate buffer from pool
PoolPtr buf = GetBuffer();
if (!buf) {
return nullptr;
}
// Manually construct UDP/IP headers
uint8_t* pData = (uint8_t*)buf->pData;
// IP header setup (simplified - actual code more complex)
struct IPHeader* ipHdr = (struct IPHeader*)pData;
ipHdr->version = 4;
ipHdr->protocol = UDP_PROTOCOL;
// ... more header fields ...
// UDP header setup
struct UDPHeader* udpHdr = (struct UDPHeader*)(pData + IP_HEADER_SIZE);
udpHdr->srcPort = htons(5000);
udpHdr->dstPort = htons(6000);
udpHdr->length = htons(len + UDP_HEADER_SIZE);
// ... checksum calculation ...
// Copy payload
memcpy(pData + IP_HEADER_SIZE + UDP_HEADER_SIZE, data, len);
return buf; // Caller takes ownership
}
void SendCustomPacket() {
uint8_t payload[] = "Custom data";
PoolPtr buf = CreateCustomUDPPacket(payload, sizeof(payload));
if (buf) {
UDPPacket pkt(buf); // Wrap buffer - takes ownership
// pkt will auto-free buffer when destroyed
// Can still use normal UDPPacket methods
printf("Packet size: %u\r\n", pkt.GetDataSize());
}
}
PoolPtr GetBuffer()
Allocate a software buffer for general use.
#define IP_HEADER_SIZE
Definition constants.h:76
#define UDP_HEADER_SIZE
Definition constants.h:79
Example Usage - Raw Packet Inspection:
// Intercept packets at low level for inspection
void InspectRawPacket(PoolPtr rawBuffer) {
// Create temporary packet wrapper for inspection
// Note: This takes ownership of rawBuffer!
UDPPacket pkt(rawBuffer);
printf("Source: %s:%u\r\n",
pkt.GetSourceAddress().ToString(),
pkt.GetSourcePort());
printf("Destination: %s:%u\r\n",
pkt.GetDestinationAddress().ToString(),
pkt.GetDestinationPort());
printf("Data size: %u bytes\r\n", pkt.GetDataSize());
// Buffer will be freed when pkt goes out of scope
}

Common Mistakes to Avoid:
// WRONG - Double free!
UDPPacket pkt(buf);
FreeBuffer(buf); // CRASH - pkt already owns it!
// WRONG - Using buffer after transfer
UDPPacket pkt(buf);
buf->pData[0] = 0xFF; // UNDEFINED - pkt owns buffer now!
// WRONG - Uninitialized buffer
UDPPacket pkt(buf); // CRASH - no valid UDP/IP headers!
// CORRECT - Proper ownership transfer
PoolPtr buf = CreateValidPacketBuffer();
UDPPacket pkt(buf); // Clean transfer
// Don't touch buf anymore
void FreeBuffer(PoolPtr nbuf)
Free a buffer and return it to the unused pool.
For Most Applications:
You should NOT use this constructor. Use these instead:
  • UDPPacket() - Standard packet creation
  • UDPPacket(bool) - IPv4/IPv6 packet creation
See also
UDPPacket(), UDPPacket(bool), PoolPtr, GetBuffer(), FreeBuffer()

◆ UDPPacket() [4/5]

UDPPacket::UDPPacket ( UDPPacket & pkt)

Move constructor - transfers ownership.

Constructs a new UDPPacket by moving resources from an existing packet. The source packet transfers ownership of its internal buffers and state to the new packet. After the move, the source packet becomes invalid and should not be used.

Parameters
pktSource packet to move from (will be invalidated)
Note
Source packet becomes INVALID after move - do not use it!
This is a move operation, not a copy - no data duplication occurs
Useful for returning packets from functions efficiently
No memory allocation or copying happens - just ownership transfer
The source packet should be considered destroyed after the move
Move Semantics:
After construction:
  • New packet: Has all data and state from source
  • Source packet: Empty/invalid state, should not be accessed
Typical Use Cases:
  • Returning UDPPacket from a function without copying
  • Transferring packet ownership between objects
  • Building packets in helper functions
  • Factory pattern implementations
  • Avoiding unnecessary buffer copies

Expand for Example Usage

Examples

Example Usage - Return from Function:
// Build a packet and return it efficiently (no copy)
UDPPacket CreateStatusPacket(uint32_t statusCode) {
UDPPacket pkt;
pkt.SetDestinationPort(8080);
pkt.AddDataWord(statusCode);
pkt.AddData("Status update", 13);
return pkt; // Move constructor called automatically
}
void SendStatus() {
UDPPacket statusPkt = CreateStatusPacket(200); // Moved, not copied
statusPkt.Send(serverIP);
}
Example Usage - Packet Factory Pattern:
class PacketBuilder {
public:
// Returns packet by move - efficient
UDPPacket BuildHeartbeat(uint32_t sequence) {
UDPPacket pkt;
pkt.SetDestinationPort(5000);
pkt.AddDataByte(0x01); // Heartbeat type
pkt.AddDataWord(sequence);
pkt.AddDataWord(Secs); // Timestamp
return pkt; // Move constructor invoked
}
UDPPacket BuildDataPacket(const uint8_t* data, uint16_t len) {
UDPPacket pkt;
pkt.SetDestinationPort(5001);
pkt.AddDataByte(0x02); // Data type
pkt.AddData((puint8_t)data, len);
return pkt; // Move constructor invoked
}
};
void SendPackets() {
PacketBuilder builder;
UDPPacket hb = builder.BuildHeartbeat(42); // Moved
hb.Send(serverIP);
uint8_t data[] = {1, 2, 3, 4};
UDPPacket dp = builder.BuildDataPacket(data, 4); // Moved
dp.Send(serverIP);
}
void AddDataByte(uint8_t b)
Add 8-bit value.
Example Usage - Conditional Packet Building:
UDPPacket PreparePacket(bool urgent) {
UDPPacket pkt;
if (urgent) {
pkt.SetDSCP(46); // Expedited Forwarding
pkt.SetDestinationPort(9000);
pkt.AddData("URGENT", 6);
} else {
pkt.SetDSCP(0); // Best effort
pkt.SetDestinationPort(9001);
pkt.AddData("NORMAL", 6);
}
return pkt; // Move constructor - no copy overhead
}
void ProcessAlert(bool isUrgent) {
UDPPacket alertPkt = PreparePacket(isUrgent); // Efficient move
alertPkt.Send(monitorIP);
}
void SetDSCP(uint8_t dscp)
Set DSCP for QoS (0=best effort, 46=VoIP/EF, 34=video/AF41, 8=bulk/CS1)
Example Usage - Packet Queue Transfer:
// Transfer packets between queues efficiently
void MovePacketToQueue(UDPPacket& sourcePkt, std::vector<UDPPacket>& queue) {
UDPPacket movedPkt(sourcePkt); // Move constructor
queue.push_back(movedPkt);
// sourcePkt is now invalid - don't use it!
}

Performance Benefits:
// WITHOUT move constructor (hypothetical copy)
UDPPacket CreatePacket() {
UDPPacket pkt;
pkt.AddData(largeBuffer, 1024);
return pkt; // Would copy 1024+ bytes!
}
// WITH move constructor (actual behavior)
UDPPacket CreatePacket() {
UDPPacket pkt;
pkt.AddData(largeBuffer, 1024);
return pkt; // Just transfers pointer - fast!
}
What Happens During Move:
  1. New packet receives all internal pointers from source
  2. New packet receives all state (ports, addresses, data size)
  3. Source packet's pointers are set to NULL/invalid
  4. Source packet should not be accessed after move
  5. No memory copying or allocation occurs
Warning
CRITICAL: After move, the source packet is INVALID
UDPPacket pkt1;
pkt1.AddData("Hello", 5);
UDPPacket pkt2(pkt1); // Move from pkt1 to pkt2
// SAFE - pkt2 has the data
pkt2.Send(serverIP);
// UNSAFE - pkt1 is now invalid!
pkt1.Send(serverIP); // UNDEFINED BEHAVIOR!
Compiler Optimization:
Modern compilers often use Return Value Optimization (RVO) or Named Return Value Optimization (NRVO) to eliminate even the move constructor call, constructing the return value directly in the caller's location. The move constructor exists as a fallback when such optimizations can't be applied.
See also
UDPPacket(), UDPPacket(bool), Send(), AddData()

◆ UDPPacket() [5/5]

UDPPacket::UDPPacket ( bool bIsIpv6 = false)

Construct a new UDP packet object.

Creates a UDP packet object that can be used for sending or receiving UDP data. The packet is allocated with appropriate buffer space and initialized for either IPv4 or IPv6 operation.

Parameters
bIsIpv6IP version selector:
  • false = IPv4 packet (default, most common)
  • true = IPv6 packet (128-bit addresses)
Note
The default is IPv4 (bIsIpv6=false) which is appropriate for most applications
For received packets, the IP version is automatically detected regardless of constructor parameter
The same UDPPacket object can be reused for multiple send/receive operations
Memory is allocated during construction - consider reusing packets in loops
When to Use IPv6:
  • Your network infrastructure requires IPv6 addressing
  • Communicating with IPv6-only hosts
  • Future-proofing for IPv6 transition
  • Link-local communication using fe80:: addresses
IPv4 vs IPv6 Considerations:
Feature IPv4 (false) IPv6 (true)
Address Size 32-bit (4 bytes) 128-bit (16 bytes)
Address Format 192.168.1.100 fe80::1234:5678:abcd:ef01
Header Size 20 bytes minimum 40 bytes minimum
Typical Use Most networks today Modern/future networks

Expand for Example Usage

Examples

Example Usage - Basic IPv4 Packet (Default):
// Create IPv4 packet (most common case)
UDPPacket pkt; // IPv4 by default
pkt.AddData("Hello", 5);
pkt.Send(serverIP);
Example Usage - Explicit IPv4:
// Explicitly specify IPv4
UDPPacket pkt(false);
pkt.SetSourcePort(5000);
while (running) {
if (pkt.Receive(&fifo, TICKS_PER_SECOND)) {
if (pkt.Validate()) {
ProcessIPv4Packet(pkt);
}
}
}
Example Usage - IPv6 Packet:
// Create IPv6 packet for modern networks
UDPPacket pkt(true); // IPv6 mode
// IPv6 address example
IPADDR ipv6Addr;
ipv6Addr.SetFromAscii("fe80::1234:5678:abcd:ef01");
pkt.AddData("IPv6 Data", 9);
pkt.Send(ipv6Addr);
void SetFromAscii(const char *cp, bool bembed_v4addresses=true)
Set the IP address value of an IPADDR6 object.
Example Usage - Dual-Stack Application:
// Support both IPv4 and IPv6
void ProcessPackets(OS_FIFO *fifo, bool useIPv6) {
UDPPacket pkt(useIPv6); // Construct with appropriate version
while (running) {
if (pkt.Receive(fifo, TICKS_PER_SECOND)) {
if (pkt.Validate()) {
// Check actual packet type
if (pkt.bIsIPV6()) {
printf("IPv6 packet received\r\n");
} else {
printf("IPv4 packet received\r\n");
}
ProcessPacket(pkt);
}
}
}
}
// In main application
if (networkSupportsIPv6()) {
ProcessPackets(&fifo, true); // IPv6
} else {
ProcessPackets(&fifo, false); // IPv4
}
bool bIsIPV6() const
Check if packet uses IPv6 addressing.
Definition udp.h:2599
Example Usage - Efficient Packet Reuse:
// Create packet once, reuse many times (recommended pattern)
UDPPacket pkt; // IPv4 packet
// Send multiple messages efficiently
for (int i = 0; i < 100; i++) {
pkt.ResetData(); // Clear previous data
pkt.AddDataWord(i);
pkt.AddData("Message", 7);
pkt.Send(destIP, destPort);
OSTimeDly(TICKS_PER_SECOND);
}
// Same packet object can also receive
while (running) {
if (pkt.Receive(&fifo, TICKS_PER_SECOND * 5)) {
if (pkt.Validate()) {
ProcessResponse(pkt);
}
}
}
void ResetData(void)
Reset data size to 0 (clears packet)

Performance Tip:
For high-performance applications, create the UDPPacket object once outside your main loop and reuse it:
// INEFFICIENT - Creates/destroys packet each iteration
while (running) {
UDPPacket pkt; // Allocation overhead!
if (pkt.Receive(&fifo, timeout)) {
// process
}
}
// EFFICIENT - Create once, reuse many times
UDPPacket pkt; // Allocated once
while (running) {
if (pkt.Receive(&fifo, timeout)) {
// process (much faster!)
}
}
Warning
For received packets, the IP version is determined by the incoming packet, not by the constructor parameter. Use bIsIPV6() to check received packet type.
See also
bIsIPV6(), Receive(), Send(), ResetData()

◆ ~UDPPacket()

UDPPacket::~UDPPacket ( )

Destructor - automatically frees pool buffer.

Destructor that automatically releases the UDP packet's pool buffer back to the system memory pool. This implements RAII (Resource Acquisition Is Initialization) principles, ensuring proper cleanup without manual memory management.

Note
Automatic cleanup - Called automatically when packet goes out of scope
No manual calls needed - Never call this destructor directly
Exception-safe - Cleanup happens even if exceptions occur
Pool buffer release - Returns buffer to pool for reuse
Warning
If Send() was already called, the buffer is already freed - destructor handles this
Do not access packet data after the UDPPacket object is destroyed
Buffer is NOT freed if SendAndKeep() was the last send operation
RAII Benefits:
Resource Acquisition Is Initialization provides automatic memory management:
  • Allocation: Constructor allocates pool buffer
  • Usage: Packet methods use the buffer
  • Cleanup: Destructor automatically frees buffer
  • Safety: No memory leaks even with exceptions
When Destructor Runs:
The destructor is automatically called when:
  • UDPPacket goes out of scope
  • UDPPacket is explicitly deleted
  • Function returns (for local variables)
  • Exception is thrown (stack unwinding)
  • Container is destroyed (if packet in vector, etc.)
Memory Management Cases:
The destructor handles different memory states correctly:

Case 1: Buffer never sent

{
UDPPacket pkt;
pkt.AddData("Hello", 5);
// Destructor frees buffer when pkt goes out of scope
}

Case 2: Buffer sent with Send()

{
UDPPacket pkt;
pkt.AddData("Hello", 5);
pkt.Send(destIP); // Buffer already freed here
// Destructor sees buffer is NULL, does nothing
}

Case 3: Buffer sent with SendAndKeep()

{
UDPPacket pkt;
pkt.AddData("Hello", 5);
pkt.SendAndKeep(dest1); // Buffer retained
pkt.SendAndKeep(dest2); // Buffer still retained
// Destructor frees buffer when pkt goes out of scope
}
void SendAndKeep(const IPADDR &to, uint8_t ttl=0)
Send copy, keep original (for sending to multiple destinations)
Definition udp.h:3195

Case 4: Exception safety

try {
UDPPacket pkt;
pkt.AddData("Hello", 5);
ThrowException(); // Exception thrown
// Destructor still called during stack unwinding - no leak
} catch (...) {
// Buffer already cleaned up by destructor
}
Performance Considerations:
  • Fast operation: Simply returns buffer to pool
  • No system calls: Pure memory pool operation
  • O(1) complexity: Constant time release
  • Thread-safe: Pool operations are synchronized

Expand for Example Usage

Examples

Common Patterns:
// Pattern 1: Local scope (most common)
void SendMessage() {
UDPPacket pkt; // Constructor allocates
pkt.AddData("Message", 7);
pkt.Send(serverIP);
} // Destructor called here - automatic cleanup
// Pattern 2: Early cleanup with explicit scope
void ProcessData() {
{
UDPPacket pkt;
pkt.Receive(&fifo, timeout);
ProcessPacket(pkt);
} // Buffer freed here, before other work
DoOtherWork(); // More memory available
}
// Pattern 3: Container of packets
void ManagePackets() {
std::vector<UDPPacket> packets;
packets.emplace_back(); // Constructor called
packets.clear(); // Destructors called for all
}
// Pattern 4: Dynamic allocation (less common)
void DynamicPacket() {
UDPPacket* pkt = new UDPPacket();
pkt->AddData("Hello", 5);
delete pkt; // Explicit destructor call
}

Destructor vs Send():
Understanding when memory is freed:
Operation Buffer State After Destructor Action
Send() Freed immediately None (already freed)
SendAndKeep() Retained Frees on destruction
No send Allocated Frees on destruction
Receive() only Allocated Frees on destruction
Fragment Buffer Handling:
#ifdef UDP_FRAGMENTS
// For fragmented packets, destructor calls FragFreeBuffer()
// instead of normal FreeBuffer() - handles reassembly cleanup
#endif
Internal Implementation:
The destructor performs these steps:
  1. Check if pool buffer pointer (m_p) is non-NULL
  2. If fragment buffer, call FragFreeBuffer()
  3. Otherwise, call FreeBuffer()
  4. Set internal pointers to NULL
  5. IPv6 cleanup if compiled with IPv6 support
Best Practices:
  • Let it work automatically - Don't call destructor manually
  • Use local variables - Simplest and safest pattern
  • Minimize lifetime - Use explicit scopes for early cleanup
  • Avoid new/delete - Prefer stack allocation
  • Trust RAII - Don't second-guess automatic cleanup
What NOT To Do:
// WRONG: Explicit destructor call
pkt.~UDPPacket(); // NEVER DO THIS!
// WRONG: Accessing after scope
UDPPacket* ptr;
{
UDPPacket pkt;
ptr = &pkt;
} // pkt destroyed here
ptr->Send(ip); // CRASH: Accessing destroyed object
// WRONG: Double-delete
UDPPacket* pkt = new UDPPacket();
delete pkt;
delete pkt; // CRASH: Double-free
~UDPPacket()
Destructor - automatically frees pool buffer.
Debug Information:
In debug builds, the destructor may:
  • Log destructor calls
  • Validate buffer state
  • Check for memory corruption
  • Track pool statistics
Warning
Critical: Never manually call the destructor unless you know exactly what you're doing
The destructor is called automatically - manual calls cause double-free bugs
See also
UDPPacket(), Send(), SendAndKeep(), FreeBuffer(), PoolPtr

Member Function Documentation

◆ AddData() [1/2]

void UDPPacket::AddData ( PCSTR pData)

Add null-terminated string (includes NULL in packet)

Appends a null-terminated string to the packet, including the terminating NULL character. This is convenient for string-based protocols where the receiver expects NULL-terminated strings.

Parameters
pDataPointer to null-terminated string to add
Note
The NULL terminator IS included in the packet data
String length is automatically calculated using strlen()
Data size is incremented by (strlen(pData) + 1)
Warning
pData must be a valid null-terminated string
For binary data that may contain NULL bytes, use AddData(puint8_t, uint16_t)
Example Usage:
pkt.AddData("HELLO"); // Adds 6 bytes: 'H','E','L','L','O','\0'
pkt.AddData("WORLD"); // Adds 6 bytes: 'W','O','R','L','D','\0'
// Packet now contains: "HELLO\0WORLD\0" (12 bytes total)
See also
AddData(puint8_t, uint16_t), GetDataSize()

◆ AddData() [2/2]

void UDPPacket::AddData ( puint8_t pData,
uint16_t len )

Add binary data (auto-updates size - no SetDataSize() needed)

Appends binary data to the packet buffer and automatically updates the internal data size counter. This is the primary method for building packets with structured data.

Parameters
pDataPointer to the binary data to add
lenNumber of bytes to copy from pData
Note
The data size is automatically incremented by len
No manual call to SetDataSize() is required
Data is appended to the end of existing packet data
Warning
Ensure pData points to at least len valid bytes
No bounds checking - caller must ensure packet has space
Example Usage:
struct SensorData {
uint32_t timestamp;
float temperature;
float humidity;
} data;
uint8_t header[] = {0xAA, 0xBB, 0x01};
pkt.AddData(header, sizeof(header));
pkt.AddData((puint8_t)&data, sizeof(data));
pkt.Send(destIP, destPort);
See also
AddData(PCSTR), AddDataWord(), AddDataByte(), GetDataSize()

◆ AddDataByte()

void UDPPacket::AddDataByte ( uint8_t b)

Add 8-bit value.

Appends a single byte to the packet. Useful for adding flags, command codes, or single-byte values to packet data.

Parameters
b8-bit value to add (0-255)
Note
Increments data size by 1 byte
No byte order conversion needed (single byte)
Example Usage:
pkt.AddDataByte(0x01); // Command code
pkt.AddDataByte(0xFF); // Flag value
pkt.AddDataByte(42); // Numeric value
See also
AddDataWord(), AddData(puint8_t, uint16_t)

◆ AddDataWord()

void UDPPacket::AddDataWord ( uint16_t w)

Add 16-bit value.

Appends a 16-bit word to the packet in network byte order (big-endian). Useful for adding integer values, ports, or length fields to packets.

Parameters
w16-bit value to add (0-65535)
Note
Value is automatically converted to network byte order if needed
Increments data size by 2 bytes
Equivalent to AddData((puint8_t)&w, 2) with byte order conversion
Example Usage:
pkt.AddDataWord(0x1234); // Adds 2 bytes: 0x12, 0x34 (big-endian)
pkt.AddDataWord(8080); // Adds port number
See also
AddDataByte(), AddData(puint8_t, uint16_t)

◆ bIsIPV6()

bool UDPPacket::bIsIPV6 ( ) const
inline

Check if packet uses IPv6 addressing.

Determines whether this packet is using IPv6 or IPv4 addressing by checking if the internal IPv6 header pointer is set. Returns true for IPv6 packets, false for IPv4 packets.

Returns
true if packet is IPv6, false if packet is IPv4
Note
This is a const function and does not modify the packet
The check is performed by testing if m_pIP6f (IPv6 header pointer) is NULL
Use this before making IP version-specific operations
Why Check IP Version?
  • IPv6 addresses are 128-bit vs IPv4's 32-bit
  • Some protocols behave differently on IPv6
  • MTU and fragmentation differ between versions
  • Useful for logging and debugging
  • May need different processing for IPv4 vs IPv6

Expand for Example Usage

Examples

Example Usage:
if (pkt.Receive()) {
IPADDR source = pkt.GetSourceAddress();
if (pkt.bIsIPV6()) {
printf("IPv6 packet from: %s\r\n", source.ToString());
ProcessIPv6Specific(pkt);
} else {
printf("IPv4 packet from: %s\r\n", source.ToString());
ProcessIPv4Specific(pkt);
}
}
// Conditional packet handling
if (!pkt.bIsIPV6() && requireIPv6Only) {
printf("Rejecting IPv4 packet on IPv6-only interface\r\n");
return;
}
IPADDR GetSourceAddress(void)
Get source IP address of the packet.
Definition udp.h:2496

See also
GetSourceAddress(), GetDestinationAddress(), IPADDR::IsIPv6()

◆ GetDataBuffer()

puint8_t UDPPacket::GetDataBuffer ( bool bReAllocateIfNeeded = false)

Get data buffer pointer for reading or writing.

CRITICAL: After writing, MUST call SetDataSize() before sending!

// Writing (sprintf method - recommended for text):
uint16_t len = sprintf(pkt.GetDataBuffer(), "Value: %d", val);
pkt.SetDataSize(len); // REQUIRED!
// Reading (received packets):
puint8_t data = pkt.GetDataBuffer();
uint16_t len = pkt.GetDataSize();
for (int i = 0; i < len; i++) { process(data[i]); }

◆ GetDataSize()

uint16_t UDPPacket::GetDataSize ( void ) const

Get current data size in bytes.

Returns the number of bytes currently stored in the packet's data buffer. This reflects the actual data length, not the buffer capacity.

Returns
Current data size in bytes (0 to maximum packet size)
Note
This is a const function and does not modify the packet state
The returned size includes all data added via AddData() methods
Example Usage:
UDPPacket packet;
packet.AddData("Test", 4);
uint16_t size = packet.GetDataSize(); // Returns 4
uint16_t GetDataSize(void) const
Get current data size in bytes.
See also
ResetData(), AddData()

◆ GetDestinationAddress()

IPADDR UDPPacket::GetDestinationAddress ( void )
inline

Get destination IP address of the packet.

Returns the destination IP address from the packet header. For received packets, this is YOUR local interface address that received the packet (useful for multi-homed devices). For outgoing packets, this is the target remote address.

Returns
IPADDR object containing the destination address (IPv4 or IPv6)
Note
This function wraps GetDestinationAddress6() for unified IPv4/IPv6 handling
For received packets: returns YOUR local IP that received it
For sent packets: returns the remote target IP you're sending to
Useful for determining which interface received a packet
Understanding Address Roles:
For Received Packets:

For Sent Packets:

Example Usage:
if (pkt.Receive()) {
IPADDR myAddr = pkt.GetDestinationAddress();
IPADDR senderAddr = pkt.GetSourceAddress();
// Useful for multi-homed devices
if (myAddr == primaryInterface) {
ProcessPrimaryNetwork(pkt);
} else if (myAddr == managementInterface) {
ProcessManagementNetwork(pkt);
}
printf("Packet from %s to my interface %s\r\n",
senderAddr.ToString(),
myAddr.ToString());
}
IPADDR GetDestinationAddress(void)
Get destination IP address of the packet.
Definition udp.h:2543
See also
GetSourceAddress(), GetDestinationPort(), GetDestinationAddress6()

◆ GetDestinationPort()

uint16_t UDPPacket::GetDestinationPort ( void ) const

Get destination port (for received packets: local port that received it)

For outgoing packets, returns the destination port set by SetDestinationPort(). For received packets, returns the LOCAL port that received the packet (i.e., which port on YOUR device the packet was addressed to).

Returns
Port number (1-65535)
Note
For received packets, this is YOUR listening port, not the sender's port
To get the sender's port on received packets, use GetSourcePort()
This is a const function and does not modify the packet
Understanding Port Roles in Received Packets:
When you receive a UDP packet:
Example Usage:
// Receiving on multiple ports
if (pkt.Receive()) {
uint16_t myPort = pkt.GetDestinationPort();
uint16_t theirPort = pkt.GetSourcePort();
if (myPort == 5000) {
ProcessControlPacket(pkt);
} else if (myPort == 5001) {
ProcessDataPacket(pkt);
}
// Reply to sender
UDPPacket reply;
reply.SetDestinationPort(theirPort);
reply.Send(pkt.GetSourceAddress());
}
uint16_t GetDestinationPort(void) const
Get destination port (for received packets: local port that received it)
uint16_t GetSourcePort(void) const
Get source port from received packet or previously set value.
See also
SetDestinationPort(), GetSourcePort(), GetSourceAddress()

◆ GetDSCP()

uint8_t UDPPacket::GetDSCP ( void ) const

Get DSCP value (0-63)

Returns the Differentiated Services Code Point (DSCP) value from the packet's IP header. DSCP is used for Quality of Service (QoS) classification and traffic prioritization in IP networks.

Returns
DSCP value in range 0-63
  • 0 = Best Effort (default)
  • 46 = Expedited Forwarding (EF) - low latency
  • 10,12,14 = Assured Forwarding (AF) classes
  • See RFC 2474 for complete DSCP definitions
Note
This is a const function and does not modify the packet
DSCP occupies the upper 6 bits of the IP TOS/Traffic Class field
Not all networks honor DSCP markings - depends on router configuration
Common DSCP Values:
Value Name Description
0 CS0 Best Effort (default)
8 CS1 Low Priority
46 EF Expedited Forwarding (VoIP)
34 AF41 High Priority Data
26 AF31 Medium Priority Data
Example Usage:
UDPPacket packet;
// ... receive packet ...
uint8_t dscp = packet.GetDSCP();
if (dscp == 46) {
printf("High priority packet (EF)\r\n");
} else if (dscp == 0) {
printf("Best effort packet\r\n");
}
uint8_t GetDSCP(void) const
Get DSCP value (0-63)
See also
SetDSCP(), RFC 2474 (DSCP), RFC 2475 (DiffServ Architecture)

◆ GetMacSource()

MACADR UDPPacket::GetMacSource ( )

Get sender's MAC address (link-layer identification)

Returns the source MAC address from the Ethernet frame header. This is the hardware address of the last-hop device that transmitted the packet on the local network segment.

Returns
MACADR object containing the 6-byte MAC address
Warning
The returned MAC may be a router's MAC, not the original sender's MAC, if the packet crossed subnet boundaries. Use GetSourceAddress() for end-to-end identification.
Note
Only valid for received packets - undefined for packets not yet sent
MAC address is Link Layer (Layer 2) - only valid on local network segment
For packets from remote subnets, this is the default gateway's MAC
Different from IP source address which identifies the original sender
Understanding MAC vs IP Addresses:
Attribute MAC Address IP Address
Scope Local network only End-to-end (across networks)
Identity Last-hop device Original source device
Routing Changes at each router Remains constant
Use Case Link-layer filtering Application identification
Common Use Cases:
  • Device Whitelisting: Allow only known MAC addresses
  • Local Network Detection: Identify devices on same subnet
  • ARP Table Management: Correlate IP to MAC mappings
  • Security Filtering: MAC-based access control
  • Diagnostics: Verify correct router/gateway MAC

Expand for Example Usage

Examples

Example Usage - Basic MAC Display:
if (pkt.Receive()) {
MACADR mac = pkt.GetMacSource();
printf("From MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
mac.bytes[0], mac.bytes[1], mac.bytes[2],
mac.bytes[3], mac.bytes[4], mac.bytes[5]);
}
Used to store and manipulate MAC addresses.
Definition nettypes.h:69
MACADR GetMacSource()
Get sender's MAC address (link-layer identification)
Example Usage - MAC-Based Filtering:
// Whitelist of allowed MACs
const MACADR trustedDevices[] = {
{{0x00, 0x03, 0xF4, 0x12, 0x34, 0x56}}, // Device 1
{{0x00, 0x03, 0xF4, 0x78, 0x9A, 0xBC}} // Device 2
};
if (pkt.Receive()) {
MACADR sourceMac = pkt.GetMacSource();
bool trusted = false;
for (int i = 0; i < sizeof(trustedDevices)/sizeof(MACADR); i++) {
if (memcmp(&sourceMac, &trustedDevices[i], sizeof(MACADR)) == 0) {
trusted = true;
break;
}
}
if (trusted) {
ProcessPacket(pkt);
} else {
printf("Rejected packet from untrusted MAC\r\n");
}
}
Example Usage - Detecting Local vs Remote Packets:
if (pkt.Receive()) {
MACADR sourceMac = pkt.GetMacSource();
MACADR gatewayMac = GetDefaultGatewayMAC(); // Your function
if (memcmp(&sourceMac, &gatewayMac, sizeof(MACADR)) == 0) {
printf("Packet came through router (remote subnet)\r\n");
} else {
printf("Packet from device on local subnet\r\n");
}
}

MAC Address Format:
The MACADR structure contains 6 bytes (48 bits):
  • Bytes 0-2: OUI (Organizationally Unique Identifier) - manufacturer ID
  • Bytes 3-5: NIC (Network Interface Controller) - device-specific
  • Example: 00:03:F4 = NetBurner OUI
See also
GetSourceAddress(), GetMacDestination(), MACADR

◆ GetPacketId()

uint16_t UDPPacket::GetPacketId ( void )

Get IP packet ID (used for fragment reassembly and packet tracking)

Returns the IP packet identification field from the IP header. This value is used by the network stack for IP fragmentation/reassembly and can be used by applications for packet tracking and debugging.

Returns
16-bit packet ID value (0-65535)
  • Unique (or semi-unique) identifier for this IP packet
  • Typically increments for each packet sent
  • Same ID used for all fragments of a fragmented packet
Note
The packet ID is automatically assigned by the network stack for sent packets
For received packets, reflects the ID assigned by the sender
Not guaranteed to be globally unique - only useful within a short time window
Common Use Cases:
  • Fragment Reassembly: Matching fragments of the same original packet
  • Packet Tracking: Correlating packets in logs and network captures
  • Debugging: Identifying specific packets in network analysis
  • Duplicate Detection: Identifying retransmitted packets
Example Usage:
pkt.AddData("Test", 4);
pkt.Send(destIP, destPort);
uint16_t packetId = pkt.GetPacketId();
printf("Sent packet with ID: %u\r\n", packetId);
// Later, when receiving response
UDPPacket response;
if (response.Receive()) {
uint16_t responseId = response.GetPacketId();
printf("Received packet with ID: %u\r\n", responseId);
}
uint16_t GetPacketId(void)
Get IP packet ID (used for fragment reassembly and packet tracking)
Warning
Do not use packet ID as a reliable sequence number - use application-level sequencing
Packet IDs may wrap around after 65535 packets
See also
RFC 791 (IP), RFC 815 (IP Reassembly)

◆ GetSourceAddress()

IPADDR UDPPacket::GetSourceAddress ( void )
inline

Get source IP address of the packet.

Returns the source IP address from the packet header. For received packets, this is the address of the remote sender. For outgoing packets, this is the local interface address used to send the packet.

Returns
IPADDR object containing the source address (IPv4 or IPv6)
Note
This function wraps GetSourceAddress6() for unified IPv4/IPv6 handling
The returned IPADDR type supports both IPv4 and IPv6 addresses
For received packets, use this to determine who sent the packet
For sent packets, this reflects which local interface was used
Typical Use Cases:
  • Identifying the sender of a received packet
  • Validating packets are from expected sources
  • Building reply packets to the correct address
  • Logging packet sources for debugging
Example Usage:
if (pkt.Receive()) {
IPADDR senderAddr = pkt.GetSourceAddress();
uint16_t senderPort = pkt.GetSourcePort();
printf("Received from %s:%u\r\n",
senderAddr.IsIPv6() ? "IPv6" : "IPv4",
senderPort);
// Send reply back to sender
UDPPacket reply;
reply.AddData("ACK", 3);
reply.SetDestinationPort(senderPort);
reply.Send(senderAddr);
}
See also
GetDestinationAddress(), GetSourcePort(), GetSourceAddress6()

◆ GetSourcePort()

uint16_t UDPPacket::GetSourcePort ( void ) const

Get source port from received packet or previously set value.

Returns the source port from the packet's UDP header. The meaning depends on whether this is a received packet or one you're preparing to send.

Returns
Port number (0-65535)
  • For received packets: sender's port (where they sent FROM)
  • For outgoing packets: your local port (set via SetSourcePort or auto-assigned)
Note
This is a const function and does not modify the packet
For received packets, this is the REMOTE sender's port - use this to reply
For outgoing packets, returns the port you set or 0 if auto-assigned
Essential for implementing request/response patterns
Understanding Port Roles in Received Packets:
When you receive a UDP packet:
Common Use Cases:
  • Reply Routing: Getting sender's port to send response back
  • Connection Tracking: Identifying which client sent a request
  • Port Filtering: Accepting packets only from specific source ports
  • Logging: Recording which port clients are using
  • Security: Validating source port is in expected range

Expand for Example Usage

Examples

Example Usage - Server Replying to Client:
// Server receives request and replies to client
UDPPacket request;
if (request.Receive()) {
IPADDR clientAddr = request.GetSourceAddress();
uint16_t clientPort = request.GetSourcePort(); // Where to reply
printf("Request from %s:%u\r\n",
clientAddr.ToString(), clientPort);
// Send response back to client
UDPPacket response;
response.SetDestinationPort(clientPort); // Use client's port
response.AddData("ACK", 3);
response.Send(clientAddr);
}
Example Usage - Port-Based Request Routing:
// Different handlers based on which port client used
if (pkt.Receive()) {
uint16_t clientPort = pkt.GetSourcePort();
// Some protocols use specific source port ranges
if (clientPort >= 49152 && clientPort <= 65535) {
// Ephemeral port - typical client
ProcessNormalRequest(pkt);
} else if (clientPort == 5000) {
// Specific port - might be peer-to-peer
ProcessPeerRequest(pkt);
} else {
printf("Unusual source port: %u\r\n", clientPort);
}
}
Example Usage - Session Tracking:
// Track multiple clients by IP:Port combination
struct ClientSession {
IPADDR addr;
uint16_t port;
uint32_t lastSeen;
};
ClientSession sessions[MAX_CLIENTS];
if (pkt.Receive()) {
IPADDR clientAddr = pkt.GetSourceAddress();
uint16_t clientPort = pkt.GetSourcePort();
// Find or create session for this client
for (int i = 0; i < MAX_CLIENTS; i++) {
if (sessions[i].addr == clientAddr &&
sessions[i].port == clientPort) {
sessions[i].lastSeen = Secs; // Update timestamp
ProcessKnownClient(pkt, &sessions[i]);
break;
}
}
}
Example Usage - Security Filtering:
// Only accept packets from high ports (non-privileged clients)
if (pkt.Receive()) {
uint16_t sourcePort = pkt.GetSourcePort();
if (sourcePort < 1024) {
printf("Rejecting packet from privileged port %u\r\n", sourcePort);
return; // Ignore packets from system ports
}
ProcessPacket(pkt);
}

See also
SetSourcePort(), GetDestinationPort(), GetSourceAddress(), Send()

◆ Receive()

bool UDPPacket::Receive ( OS_FIFO * pFifo,
uint32_t wait_ticks )
inline

Reuse packet object for multiple receives (efficiency optimization)

Receives a UDP packet from the specified FIFO queue with a timeout. This function blocks until a packet arrives or the timeout expires. The same packet object can be reused across multiple receives for efficiency (avoids repeated allocation).

Parameters
pFifoPointer to OS_FIFO queue to receive from (created by RegisterUDPFifo())
wait_ticksMaximum time to wait for packet, in system ticks
  • 0 = Non-blocking (return immediately if no packet)
  • TICKS_PER_SECOND = 1 second timeout
  • 0xFFFFFFFF = Wait forever (blocking)
Returns
true if packet received successfully
false if timeout occurred or error
Note
ALWAYS call Validate() after successful receive to check packet integrity
The packet object is reused - no need to create new UDPPacket each time
Previous packet data is overwritten on each successful receive
This is the preferred receive method for production code (efficient)
Warning
Never process packet data without calling Validate() first
The pFifo must be created with RegisterUDPFifo() before use
wait_ticks=0 returns immediately - check return value before accessing data
Efficiency Benefits:
Reusing the same UDPPacket object across multiple receives:
  • Reduces memory allocation overhead - no malloc/free per packet
  • Improves cache performance - same memory addresses
  • Eliminates fragmentation - stable memory footprint
  • Faster execution - critical for high packet rates
FIFO Setup:
Before calling Receive(), you must create a FIFO for the port:
OS_FIFO udpFifo;
OSFifoInit(&udpFifo);
RegisterUDPFifo(5000, &udpFifo); // Listen on port 5000

Expand for Example Usage

Examples

Example Usage - Basic Server Loop:
// Setup
OS_FIFO udpFifo;
OSFifoInit(&udpFifo);
RegisterUDPFifo(5000, &udpFifo);
// Efficient receive loop - reuses same packet object
while (running) {
if (pkt.Receive(&udpFifo, TICKS_PER_SECOND * 2)) {
if (pkt.Validate()) {
ProcessPacket(pkt);
} else {
printf("Corrupted packet discarded\r\n");
}
} else {
// Timeout - no packet received in 2 seconds
HandleTimeout();
}
}
Example Usage - Non-Blocking Receive:
// Check for packet without blocking
if (pkt.Receive(&udpFifo, 0)) { // wait_ticks = 0
if (pkt.Validate()) {
printf("Packet received!\r\n");
ProcessPacket(pkt);
}
} else {
// No packet available right now - continue other work
DoOtherWork();
}
Example Usage - Multiple Ports:
// Listen on multiple ports with different FIFOs
OS_FIFO controlFifo, dataFifo;
OSFifoInit(&controlFifo);
OSFifoInit(&dataFifo);
RegisterUDPFifo(5000, &controlFifo); // Control port
RegisterUDPFifo(5001, &dataFifo); // Data port
UDPPacket pkt; // Reused for both ports
while (running) {
// Check control port (non-blocking)
if (pkt.Receive(&controlFifo, 0)) {
if (pkt.Validate()) {
ProcessControl(pkt);
}
}
// Check data port (100ms timeout)
if (pkt.Receive(&dataFifo, TICKS_PER_SECOND / 10)) {
if (pkt.Validate()) {
ProcessData(pkt);
}
}
}
Example Usage - Heartbeat with Timeout:
uint32_t lastPacketTime = Secs;
const uint32_t HEARTBEAT_TIMEOUT = 10; // seconds
while (running) {
// Wait up to 1 second for packet
if (pkt.Receive(&udpFifo, TICKS_PER_SECOND)) {
if (pkt.Validate()) {
lastPacketTime = Secs;
ProcessPacket(pkt);
}
}
// Check for heartbeat timeout
if ((Secs - lastPacketTime) > HEARTBEAT_TIMEOUT) {
printf("Connection lost - no packets for %lu seconds\r\n",
Secs - lastPacketTime);
HandleConnectionLost();
lastPacketTime = Secs; // Reset timer
}
}

Timeout Values:
wait_ticks Value Behavior Use Case
0 Non-blocking Polling, multi-tasking
TICKS_PER_SECOND / 10 100ms Responsive UI updates
TICKS_PER_SECOND 1 second Typical network timeout
TICKS_PER_SECOND * 5 5 seconds Slow networks, retries
0xFFFFFFFF Forever Dedicated receive threads
Performance Comparison:
// INEFFICIENT - Creates new packet each iteration
while (running) {
UDPPacket pkt; // BAD: Allocates memory every loop
if (pkt.Receive(&fifo, timeout)) {
// process
}
}
// EFFICIENT - Reuses same packet object
UDPPacket pkt; // GOOD: Allocated once
while (running) {
if (pkt.Receive(&fifo, timeout)) {
// process (much faster!)
}
}
See also
Validate(), RegisterUDPFifo(), OSFifoInit(), Send()

◆ ResetData()

void UDPPacket::ResetData ( void )

Reset data size to 0 (clears packet)

This function resets the packet's data length to zero, effectively clearing the packet contents without deallocating memory. The packet buffer remains allocated and can be reused for new data.

Note
This does not free memory or destroy the packet object
The packet buffer remains valid and can be immediately reused
Does not reset packet metadata (addresses, ports, flags, etc.)
Warning
After calling this function, the packet contains no valid data. Any previous data references become invalid.
Typical Use Cases:
  • Reusing a packet buffer for multiple transmissions
  • Clearing received data before processing new packets
  • Resetting packet state in error conditions
Example Usage:
UDPPacket packet;
packet.AddData("Hello", 5);
packet.Send(destIP, destPort);
// Reuse the same packet
packet.ResetData();
packet.AddData("World", 5);
packet.Send(destIP, destPort);
See also
Validate()

◆ Send()

void UDPPacket::Send ( const IPADDR & to,
uint8_t ttl = 0 )
inline

Send and free buffer (recommended - most efficient)

Sends the packet to the specified destination and immediately frees the buffer. This is the standard, most efficient way to send UDP packets. After calling this function, the packet buffer is freed and the UDPPacket object should not be used for sending again (though it can receive new data).

Parameters
toDestination IP address (IPv4 or IPv6)
ttlTime-to-live value for packet (0 = use default TTL, typically 64)
  • 0: Use system default TTL
  • 1: Local subnet only
  • 32-64: Typical for Internet routing
  • 255: Maximum (unrestricted)
Note
This function wraps Send6() for unified IPv4/IPv6 handling
Buffer is FREED immediately after send - most memory efficient
This is the recommended send method for single-destination packets
After Send(), destructor has nothing to clean up
Cannot send to additional destinations after this call
Warning
Do NOT access packet buffer after calling Send()
Do NOT call Send() multiple times on the same packet
Use SendAndKeep() instead if sending to multiple destinations
Use Cases:
  • Standard single-destination UDP send (most common)
  • Client sending request to server
  • Server sending response to client
  • Any scenario with one recipient
  • When memory efficiency is important
Typical Pattern:
The most common UDP send pattern:
pkt.SetSourcePort(5000);
pkt.AddData("REQUEST", 7);
pkt.Send(serverIP); // Send and free - done!
Memory Efficiency:
Send() immediately:
Allocate -> Fill -> Send -> Free (minimal memory footprint)
Allocate -> Fill -> Copy+Send -> Copy+Send -> Free (higher footprint)

Expand for Example Usage

Examples

Example - Simple Request/Response:
// Send request
UDPPacket request;
request.SetDestinationPort(5000);
request.AddData("GET_STATUS", 10);
request.Send(serverIP); // Buffer freed here
// Receive response
OS_FIFO responseFifo;
OSFifoInit(&responseFifo);
RegisterUDPFifo(0, &responseFifo);
UDPPacket response;
if (response.Receive(&responseFifo, TICKS_PER_SECOND * 5)) {
if (response.Validate()) {
ProcessResponse(response);
}
}
Example - Sensor Data Transmission:
void SendSensorReading(float temperature, float humidity) {
struct SensorData {
uint32_t timestamp;
float temp;
float humid;
} data = {Secs, temperature, humidity};
UDPPacket pkt;
pkt.SetDestinationPort(6000);
pkt.AddData((puint8_t)&data, sizeof(data));
pkt.Send(dataCollectorIP); // Efficient single send
}
Example - Efficient Batch Sending:
// Reuse packet for multiple separate sends
for (int i = 0; i < 100; i++) {
pkt.ResetData();
pkt.AddDataWord(i);
pkt.AddData("Data packet", 11);
pkt.Send(serverIP); // Each send frees buffer
OSTimeDly(TICKS_PER_SECOND / 10); // 100ms between packets
}

Performance Comparison:
Method Memory Speed Use When
Send() Low Fast Single destination
SendAndKeep() High Slower Multiple destinations
TTL Common Values:
// Local subnet only (TTL=1)
pkt.Send(localIP, 1);
// Standard Internet (TTL=0, uses default ~64)
pkt.Send(remoteIP, 0);
// Extended reach (TTL=128)
pkt.Send(distantIP, 128);
Lifecycle Comparison:
// Method 1: Send() - Simple and efficient
{
UDPPacket pkt;
pkt.AddData("Hello", 5);
pkt.Send(dest); // Buffer freed here
} // Destructor has nothing to do
// Method 2: No Send() - Destructor cleans up
{
UDPPacket pkt;
pkt.AddData("Hello", 5);
// Forgot to send?
} // Destructor frees buffer (but packet never sent!)
// Method 3: SendAndKeep() - More complex
{
UDPPacket pkt;
pkt.AddData("Hello", 5);
pkt.SendAndKeep(dest1); // Buffer still allocated
pkt.Send(dest2); // Buffer freed here
} // Destructor has nothing to do
Common Mistakes:
// WRONG: Trying to send after Send()
pkt.AddData("Hello", 5);
pkt.Send(dest1); // Buffer freed
pkt.Send(dest2); // CRASH: Buffer already freed!
// CORRECT: Use SendAndKeep() for multiple
pkt.AddData("Hello", 5);
pkt.SendAndKeep(dest1); // Buffer retained
pkt.Send(dest2); // Buffer freed
// WRONG: Accessing buffer after Send()
pkt.AddData("Hello", 5);
pkt.Send(dest);
pkt.AddData("More", 4); // CRASH: Buffer gone!
// CORRECT: Reset and reuse packet
pkt.AddData("Hello", 5);
pkt.Send(dest);
// Wait for new data or receive
pkt.Receive(&fifo, timeout); // Gets new buffer
Best Practices:
  • Default choice: Use Send() for single-destination packets
  • Memory efficient: Frees buffer immediately
  • Simple pattern: Allocate -> Fill -> Send -> Done
  • Reusable packet: Can receive new data after Send()
  • Clear ownership: Buffer freed, no ambiguity
See also
SendAndKeep(), SendViaInterfaceNum(), AddData(), SetDestinationPort()

◆ SendAndKeep()

void UDPPacket::SendAndKeep ( const IPADDR & to,
uint8_t ttl = 0 )
inline

Send copy, keep original (for sending to multiple destinations)

Sends a copy of the packet to the specified destination while retaining the original buffer for additional sends. This is essential when sending the same packet to multiple destinations. The buffer remains allocated until either Send() is called or the packet is destroyed.

Parameters
toDestination IP address (IPv4 or IPv6)
ttlTime-to-live value for packet (0 = use default TTL, typically 64)
  • 0: Use system default TTL
  • 1: Local subnet only
  • 32-64: Typical for Internet routing
  • 255: Maximum (unrestricted)
Note
This function wraps SendAndKeep6() for unified IPv4/IPv6 handling
Buffer is RETAINED after send - you must eventually call Send() or let destructor run
Each call creates a new copy of the packet data
Less efficient than Send() due to buffer copying
Use when you need to send the same data to multiple recipients
Warning
Must eventually free buffer with Send() or allow destructor to run
Memory leak if you only use SendAndKeep() and never Send()
Each SendAndKeep() allocates a new buffer - don't use in tight loops
Use Cases:
  • Sending same data to multiple servers (redundancy)
  • Broadcasting to multiple monitoring stations
  • Fan-out messaging patterns
  • Multicast alternative for small recipient lists
  • Logging to multiple destinations
Typical Pattern:
Always end with Send() to free the buffer:
pkt.AddData("Alert: System temperature high", 30);
pkt.SendAndKeep(server1); // Copy sent, buffer kept
pkt.SendAndKeep(server2); // Copy sent, buffer kept
pkt.Send(server3); // Copy sent, buffer freed
// Buffer automatically freed by last Send()
Memory Management:
SendAndKeep(dest1) -> Creates copy -> Sends -> Keeps original
SendAndKeep(dest2) -> Creates copy -> Sends -> Keeps original
Send(dest3) -> Sends original -> Frees buffer
OR if no final Send():
SendAndKeep(dest1) -> Creates copy -> Sends -> Keeps original
SendAndKeep(dest2) -> Creates copy -> Sends -> Keeps original
~UDPPacket() -> Destructor frees original buffer
Example - Multiple Monitoring Servers:
void SendStatusToMonitors(const char* status) {
IPADDR monitors[] = {
AsciiToIp("192.168.1.10"),
AsciiToIp("192.168.1.11"),
AsciiToIp("192.168.1.12")
};
UDPPacket pkt;
pkt.SetDestinationPort(9000);
pkt.AddData(status);
// Send to all but last
for (int i = 0; i < 2; i++) {
pkt.SendAndKeep(monitors[i]);
}
// Last send frees buffer
pkt.Send(monitors[2]);
}
Example - Redundant Server Communication:
// Send critical data to primary and backup servers
UDPPacket criticalData;
criticalData.SetDestinationPort(5000);
criticalData.AddData("CRITICAL:SHUTDOWN", 17);
criticalData.SendAndKeep(primaryServer); // Send to primary
criticalData.Send(backupServer); // Send to backup and free
Performance Considerations:
Aspect Cost Notes
Buffer copy Medium Each SendAndKeep() allocates new buffer
Network I/O High N separate transmissions
Memory Higher Temporary buffers until final Send()
Use when N is small Typically < 10 destinations
SendAndKeep() vs Send():
// SendAndKeep() - Use for multiple destinations
pkt.SendAndKeep(dest1); // Buffer retained
pkt.Send(dest2); // Buffer freed
// Send() - Use for single destination (more efficient)
pkt.Send(dest); // Buffer freed immediately
TTL Values Guide:
TTL Scope Use Case
0 System default (usually 64) Normal operation
1 Local subnet only Link-local communication
16 Limited regional Campus networks
64 Internet standard General Internet traffic
128 Extended reach Cross-continent
255 Maximum Unrestricted (rarely needed)
Common Mistakes:
// WRONG: Only SendAndKeep(), never freed
pkt.AddData("Hello", 5);
pkt.SendAndKeep(dest1);
pkt.SendAndKeep(dest2);
// Memory leak! Buffer never freed
// CORRECT: End with Send()
pkt.AddData("Hello", 5);
pkt.SendAndKeep(dest1);
pkt.Send(dest2); // Frees buffer
// ALSO CORRECT: Let destructor handle it
{
UDPPacket pkt;
pkt.AddData("Hello", 5);
pkt.SendAndKeep(dest1);
pkt.SendAndKeep(dest2);
} // Destructor frees buffer
See also
Send(), SendViaInterfaceNum(), SendAndKeepViaInterfaceNum(), ~UDPPacket()

◆ SendAndKeepViaIfAddr()

void UDPPacket::SendAndKeepViaIfAddr ( const IPADDR & to,
const IPADDR & from_ip,
uint8_t ttl = 0 )
inline

Send a packet and retain a copy via a specific interface address.

This inline function wraps SendAndKeepViaIfAddr6() to send a packet to a destination IP address while routing through a specific source interface address. The function retains a copy of the packet after sending (useful for retransmission or logging).

Parameters
toDestination IP address for the packet
from_ipSource interface IP address to use for routing the packet
ttlTime-to-live value for the packet (0 = use default TTL)
Note
This is a convenience wrapper that delegates to SendAndKeepViaIfAddr6()
The "keep" behavior suggests the packet buffer is preserved for potential reuse
See also
SendAndKeepViaIfAddr6()

◆ SendAndKeepViaInterfaceNum()

void UDPPacket::SendAndKeepViaInterfaceNum ( const IPADDR & to,
int interface,
uint8_t ttl = 0 )
inline

Send copy via specific interface, keep original.

Sends a copy of the packet via a specific network interface while retaining the original buffer. This is essential for multi-homed systems where you need to send the same packet through multiple network interfaces or send to multiple destinations via specific interfaces.

Parameters
toDestination IP address (IPv4 or IPv6)
interfaceNetwork interface number (0=first interface, 1=second, etc.)
  • 0: Primary interface (usually Ethernet 0)
  • 1: Secondary interface (Ethernet 1, WiFi, etc.)
  • 2+: Additional interfaces
ttlTime-to-live value for packet (0 = use default TTL)
  • 0: Use system default TTL
  • 1: Local subnet only
  • 32-64: Typical for Internet routing
  • 255: Maximum (unrestricted)
Note
This function wraps SendAndKeepViaInterfaceNum6() for IPv4/IPv6 support
Buffer is RETAINED after send - must eventually call Send() or rely on destructor
Each call creates a new copy of the packet data
Use when you need to send same data through multiple interfaces
Interface number must be valid (0 to GetNumberOfInterfaces()-1)
Warning
Must eventually free buffer with Send() or allow destructor to run
Invalid interface numbers may cause send to fail silently
Buffer remains allocated - potential memory pressure if many calls
Use Cases:
  • Multi-homed systems: Send via specific Ethernet port
  • Network redundancy: Send same data via multiple interfaces
  • Interface testing: Verify connectivity through specific interfaces
  • Network segregation: Management vs data networks
  • Failover systems: Primary and backup network paths
Typical Pattern:
Send via multiple interfaces, free with final Send():
pkt.AddData("Status update", 13);
// Send via interface 0 (primary network)
// Send via interface 1 (backup network)
pkt.SendViaInterfaceNum(server, 1); // Last send frees buffer
void SendViaInterfaceNum(const IPADDR &to, int interface, uint8_t ttl=0)
Send via specific interface and free buffer.
Definition udp.h:3800
void SendAndKeepViaInterfaceNum(const IPADDR &to, int interface, uint8_t ttl=0)
Send copy via specific interface, keep original.
Definition udp.h:3578

Expand for Example Usage

Examples

Example - Redundant Networks:
// System with dual Ethernet ports
void SendCriticalData(const char* data, IPADDR serverIP) {
UDPPacket pkt;
pkt.SetDestinationPort(9000);
pkt.AddData(data);
// Send via primary Ethernet
pkt.SendAndKeepViaInterfaceNum(serverIP, 0);
// Send via backup Ethernet
pkt.SendViaInterfaceNum(serverIP, 1); // Frees buffer
printf("Data sent via both interfaces\r\n");
}
Example - Network Segregation:
// Separate management and production networks
#define MGMT_INTERFACE 0
#define PROD_INTERFACE 1
void SendToMonitoring(const char* alert) {
UDPPacket pkt;
pkt.SetDestinationPort(514); // Syslog
pkt.AddData(alert);
// Send to management server via management interface
pkt.SendAndKeepViaInterfaceNum(mgmtServer, MGMT_INTERFACE);
// Send to production monitor via production interface
pkt.SendViaInterfaceNum(prodMonitor, PROD_INTERFACE);
}
Example - Interface Testing:
// Test connectivity through each interface
void TestInterfaces(IPADDR testServer) {
int numInterfaces = GetNumberOfInterfaces();
UDPPacket pkt;
pkt.SetDestinationPort(7000);
pkt.AddData("PING", 4);
for (int i = 0; i < numInterfaces - 1; i++) {
printf("Testing interface %d\r\n", i);
pkt.SendAndKeepViaInterfaceNum(testServer, i);
}
// Last interface - free buffer
pkt.SendViaInterfaceNum(testServer, numInterfaces - 1);
}

Interface Selection Strategy:
Scenario Interface Selection Reason
Primary data Interface 0 Main network connection
Management Interface 1 Isolated management network
Testing Iterate all Verify all paths working
Redundancy Multiple Ensure delivery via any path
Load balancing Round-robin Distribute traffic
Memory Management:
SendAndKeepViaIfNum(dest, 0) -> Copy -> Send via if0 -> Keep original
SendAndKeepViaIfNum(dest, 1) -> Copy -> Send via if1 -> Keep original
SendViaInterfaceNum(dest, 2) -> Send via if2 -> Free original
OR let destructor handle:
SendAndKeepViaIfNum(dest, 0) -> Copy -> Send via if0 -> Keep original
SendAndKeepViaIfNum(dest, 1) -> Copy -> Send via if1 -> Keep original
~UDPPacket() -> Destructor frees original
Checking Available Interfaces:
// Get number of interfaces
int numIfs = GetNumberOfInterfaces();
printf("System has %d network interfaces\r\n", numIfs);
// Get interface details
for (int i = 0; i < numIfs; i++) {
if (ifBlock) {
printf("Interface %d: %s\r\n", i,
ifBlock->GetIPAddr().ToString());
}
}
Network interface configuration block class for interface control and configuration.
Definition netinterface.h:245
InterfaceBlock * GetInterfaceBlock(int interface=0)
Get an InterfaceBlock control and configuration object.
Performance Considerations:
Aspect Impact Notes
Buffer copy Medium Each call allocates new buffer
Network I/O High N separate transmissions
Interface overhead Low Just routing decision
Memory Higher Temporary buffers until final send
Common Mistakes:
// WRONG: Invalid interface number
pkt.SendAndKeepViaInterfaceNum(dest, 99); // Likely invalid!
// CORRECT: Check interface exists
int numIfs = GetNumberOfInterfaces();
if (interfaceNum < numIfs) {
pkt.SendAndKeepViaInterfaceNum(dest, interfaceNum);
}
// WRONG: Never freed
pkt.SendAndKeepViaInterfaceNum(dest, 0);
pkt.SendAndKeepViaInterfaceNum(dest, 1);
// Memory leak!
// CORRECT: End with Send()
pkt.SendAndKeepViaInterfaceNum(dest, 0);
pkt.SendViaInterfaceNum(dest, 1); // Frees buffer
See also
SendViaInterfaceNum(), SendAndKeep(), Send(), GetNumberOfInterfaces(), GetInterfaceBlock()

◆ SendViaIfAddr()

void UDPPacket::SendViaIfAddr ( const IPADDR & to,
const IPADDR & from_ip,
uint8_t ttl = 0 )
inline

Send a packet via a specific interface address.

This inline function sends a packet to a destination IP address while routing through a specific source interface address. Unlike SendAndKeepViaIfAddr(), this function does not retain a copy of the packet after transmission.

Parameters
toDestination IP address for the packet
from_ipSource interface IP address to use for routing the packet
ttlTime-to-live value for the packet (0 = use default TTL)
Warning
This function appears to be recursive - it calls itself. This is likely a bug and should probably call a different underlying implementation function.
Note
The recursive call will cause a stack overflow. Verify the intended implementation.

◆ SendViaInterfaceNum()

void UDPPacket::SendViaInterfaceNum ( const IPADDR & to,
int interface,
uint8_t ttl = 0 )
inline

Send via specific interface and free buffer.

Sends the packet via a specific network interface and immediately frees the buffer. This is the standard way to send a packet through a specific interface in multi-homed systems. The buffer is freed after sending, making this the most memory-efficient option for single-interface sends.

Parameters
toDestination IP address (IPv4 or IPv6)
interfaceNetwork interface number (0=first interface, 1=second, etc.)
  • 0: Primary interface (usually Ethernet 0)
  • 1: Secondary interface (Ethernet 1, WiFi, etc.)
  • 2+: Additional interfaces
ttlTime-to-live value for packet (0 = use default TTL)
  • 0: Use system default TTL (typically 64)
  • 1: Local subnet only
  • 32-64: Typical for Internet routing
  • 255: Maximum (unrestricted)
Note
This function wraps SendViaInterfaceNum6() for IPv4/IPv6 support
Buffer is FREED immediately after send
This is the recommended method for single-interface sends
Interface number must be valid (0 to GetNumberOfInterfaces()-1)
After this call, the buffer is freed and packet cannot send again
Warning
Do NOT access packet buffer after calling this function
Do NOT call send functions multiple times on the same packet
Invalid interface numbers may cause send to fail silently
Use SendAndKeepViaInterfaceNum() if sending via multiple interfaces
Use Cases:
  • Interface-specific routing: Force packet through specific interface
  • Multi-homed systems: Separate management from production traffic
  • Network segregation: Different interfaces for different purposes
  • Testing: Verify specific interface functionality
  • Policy routing: Business rules require specific interface
Typical Pattern:
Standard single-interface send:
pkt.AddData("Status", 6);
// Send via secondary interface (e.g., management network)
pkt.SendViaInterfaceNum(serverIP, 1); // Send and free

Expand for Example Usage

Examples

Example - Management Network:
// Send management traffic via dedicated interface
#define MGMT_INTERFACE 1
void SendManagementAlert(const char* alert, IPADDR mgmtServer) {
UDPPacket pkt;
pkt.SetDestinationPort(514); // Syslog
pkt.AddData(alert);
// Send via management interface only
pkt.SendViaInterfaceNum(mgmtServer, MGMT_INTERFACE);
printf("Alert sent via management interface\r\n");
}
Example - Production Data Routing:
// Route production data via high-speed interface
#define PROD_INTERFACE 0
void SendProductionData(const uint8_t* data, uint16_t len, IPADDR dest) {
UDPPacket pkt;
pkt.SetDestinationPort(6000);
pkt.AddData(data, len);
// Force through production interface
pkt.SendViaInterfaceNum(dest, PROD_INTERFACE);
}
Example - Interface Selection Based on Destination:
void SendToDestination(const char* data, IPADDR dest) {
UDPPacket pkt;
pkt.SetDestinationPort(7000);
pkt.AddData(data);
// Choose interface based on destination
int interface;
if (IsManagementNetwork(dest)) {
interface = 1; // Management interface
} else {
interface = 0; // Production interface
}
pkt.SendViaInterfaceNum(dest, interface);
}
Example - Round-Robin Load Balancing:
// Distribute traffic across multiple interfaces
static int nextInterface = 0;
void SendLoadBalanced(const char* data, IPADDR dest) {
int numInterfaces = GetNumberOfInterfaces();
UDPPacket pkt;
pkt.SetDestinationPort(8000);
pkt.AddData(data);
// Send via next interface in rotation
pkt.SendViaInterfaceNum(dest, nextInterface);
// Move to next interface
nextInterface = (nextInterface + 1) % numInterfaces;
}

Interface Configuration Examples:
System Type Interface 0 Interface 1 Use Case
Dual Ethernet Production Management Network segregation
Ethernet + WiFi Wired Wireless Redundant connectivity
Multi-port router LAN WAN Traffic direction
Industrial system Control Data Real-time vs bulk
Verifying Interface Availability:
bool SendViaInterfaceSafe(UDPPacket& pkt, IPADDR dest, int ifNum) {
// Check if interface exists and is up
if (ifNum < 0 || ifNum >= GetNumberOfInterfaces()) {
printf("Invalid interface: %d\r\n", ifNum);
return false;
}
InterfaceBlock* ifBlock = GetInterfaceBlock(ifNum);
if (!ifBlock || !ifBlock->IsUp()) {
printf("Interface %d is down\r\n", ifNum);
return false;
}
// Interface valid and up
pkt.SendViaInterfaceNum(dest, ifNum);
return true;
}
Performance Comparison:
Method Memory Speed Complexity Use When
SendViaInterfaceNum() Low Fast Low Single interface
SendAndKeepViaIfNum() High Slower Medium Multiple interfaces
Send() (any interface) Low Fastest Lowest Don't care which interface
TTL and Routing:
// Local network via specific interface
pkt.SendViaInterfaceNum(localDest, 0, 1); // TTL=1, local only
// Internet destination via WAN interface
pkt.SendViaInterfaceNum(remoteDest, 1, 0); // TTL=default
// Extended reach via backup interface
pkt.SendViaInterfaceNum(farDest, 2, 128); // TTL=128, far reach
Common Mistakes:
// WRONG: Invalid interface number
pkt.SendViaInterfaceNum(dest, 99); // Probably invalid!
// CORRECT: Validate interface first
if (interface < GetNumberOfInterfaces()) {
pkt.SendViaInterfaceNum(dest, interface);
}
// WRONG: Trying to send again after Send()
pkt.SendViaInterfaceNum(dest, 0); // Buffer freed
pkt.SendViaInterfaceNum(dest, 1); // CRASH: Buffer gone!
// CORRECT: Use SendAndKeep() for multiple
pkt.SendAndKeepViaInterfaceNum(dest, 0); // Buffer kept
pkt.SendViaInterfaceNum(dest, 1); // Buffer freed
// WRONG: Assuming interface exists
pkt.SendViaInterfaceNum(dest, 1); // What if only 1 interface?
// CORRECT: Check interface count
int numIf = GetNumberOfInterfaces();
if (numIf > 1) {
pkt.SendViaInterfaceNum(dest, 1);
} else {
pkt.Send(dest); // Use default interface
}
Best Practices:
  • Validate interface numbers before use
  • Check interface status (up/down) before sending
  • Use for policy routing when specific path required
  • Default choice for multi-homed systems with routing requirements
  • Document interface assignments in code comments
See also
SendAndKeepViaInterfaceNum(), Send(), SendViaIfAddr(), GetNumberOfInterfaces(), GetInterfaceBlock()

◆ SetDataSize()

void UDPPacket::SetDataSize ( uint16_t numBytes)

Set data size (REQUIRED after GetDataBuffer() writes)

Maximum ~1472 bytes for standard Ethernet. Larger needs fragmentation.

// WRONG:
sprintf(pkt.GetDataBuffer(), "Hello");
pkt.Send(ip); // BUG: Size not set!
// CORRECT:
uint16_t len = sprintf(pkt.GetDataBuffer(), "Hello");
pkt.SetDataSize(len);
pkt.Send(ip);

◆ SetDestinationPort()

void UDPPacket::SetDestinationPort ( uint16_t port)

Set destination port (standard services: 53=DNS, 80=HTTP, 123=NTP, 161=SNMP)

Sets the destination UDP port for outgoing packets. The port identifies which service or application on the remote host should receive the packet.

Parameters
portDestination port number (1-65535)
  • 0 is reserved and should not be used
  • 1-1023 are well-known ports (require privileges on most systems)
  • 1024-49151 are registered ports
  • 49152-65535 are dynamic/private ports
Note
This only affects outgoing packets sent via Send()
For received packets, use GetSourcePort() to see sender's port
Common Well-Known Ports:
Port Service Description
53 DNS Domain Name System
67/68 DHCP Dynamic Host Configuration
80 HTTP Web Server
123 NTP Network Time Protocol
161 SNMP Simple Network Management
443 HTTPS Secure Web Server
1883 MQTT Message Queue Telemetry
5353 mDNS Multicast DNS

Example Usage:
pkt.SetDestinationPort(8080); // Custom application port
pkt.AddData("Hello", 5);
pkt.Send(serverIP);
See also
GetDestinationPort(), GetSourcePort(), Send()

◆ SetDSCP()

void UDPPacket::SetDSCP ( uint8_t dscp)

Set DSCP for QoS (0=best effort, 46=VoIP/EF, 34=video/AF41, 8=bulk/CS1)

Standard DSCP values (RFC 4594):

  • 0: Best Effort (default)
  • 8: CS1 (bulk data, lower priority)
  • 34: AF41 (high priority video)
  • 46: EF (VoIP, low latency/jitter)
  • 48: CS6 (network control)
pkt.SetDSCP(46); // Mark as VoIP for priority treatment
Note
Requires network QoS support to have effect

◆ SetSourcePort()

void UDPPacket::SetSourcePort ( uint16_t port)

Set source port (0=auto-assign ephemeral port, 1024-65535=specific port)

Sets the source UDP port for outgoing packets. The source port identifies which local port the packet originates from and where replies should be sent.

Parameters
portSource port number:
  • 0 = Auto-assign ephemeral port (recommended for clients)
  • 1-1023 = Well-known/system ports (avoid unless necessary)
  • 1024-49151 = Registered ports (safe for servers)
  • 49152-65535 = Dynamic/private ports (system auto-assignment range)
Note
For CLIENT applications, use 0 to let the stack auto-assign an ephemeral port
For SERVER applications, use a fixed port so clients know where to send
The stack automatically assigns ports from the ephemeral range when port=0
Setting port to 0 is equivalent to not calling this function
Port Selection Guidelines:
Application Type Recommended Port Reason
UDP Server Fixed port (e.g., 5000) Clients need to know where to send
UDP Client 0 (auto-assign) Don't care which local port is used
Peer-to-Peer Fixed port Both sides need predictable ports
Reply Packet Use 0 or leave default Stack handles reply routing
Server vs Client Pattern:
Servers listen on FIXED ports:
  • Servers: Use fixed port (e.g., 5000, 8080) so clients know where to connect
  • Must be consistent across reboots
  • Typically documented/configured value

Clients use AUTO-ASSIGNED ports:

  • Clients: Use 0 for auto-assignment - you don't care which local port
  • Different port for each connection/packet
  • Server uses GetSourcePort() from received packet to reply

Expand for Example Usage

Examples

Example Usage - UDP Server:
// Server application listening on port 5000
void ServerTask(void *pd) {
UDPPacket pkt;
pkt.SetSourcePort(5000); // Fixed port - clients send here
while (1) {
if (pkt.Receive()) {
ProcessRequest(pkt);
// Reply to client
UDPPacket reply;
reply.SetDestinationPort(pkt.GetSourcePort()); // Client's port
reply.AddData("Response", 8);
reply.Send(pkt.GetSourceAddress());
}
}
}
Example Usage - UDP Client:
// Client application sending to server
void SendRequest(IPADDR serverIP, uint16_t serverPort) {
UDPPacket pkt;
pkt.SetSourcePort(0); // Auto-assign - don't care which port
// Or just omit SetSourcePort() entirely - same effect
pkt.SetDestinationPort(serverPort); // Server's known port
pkt.AddData("Request", 7);
pkt.Send(serverIP);
}
Example Usage - Peer-to-Peer:
// Both sides use fixed ports for peer-to-peer communication
#define MY_PORT 6000
#define PEER_PORT 6000
pkt.SetSourcePort(MY_PORT); // My fixed port
pkt.SetDestinationPort(PEER_PORT); // Peer's fixed port
pkt.AddData("Hello", 5);
pkt.Send(peerIP);

Warning
Using port 0 for servers makes them unreachable - clients won't know the port
Reusing well-known ports (1-1023) may conflict with system services
Fixed ports must be available (not already in use by another application)
See also
GetSourcePort(), SetDestinationPort(), Send()

◆ Validate()

BOOL UDPPacket::Validate ( void )

Validate received packet (checks checksum and data presence)

ALWAYS call after receiving packet!

This function performs integrity checks on a received packet to ensure:

  • The packet checksum is correct (data not corrupted in transit)
  • Required data fields are present and populated
  • The packet structure is valid
Returns
true if the packet is valid and safe to process
false if the packet is corrupt, incomplete, or timed out
Warning
Failure to call this function before processing packet data may result in processing corrupted or malicious data
Note
This function should be called immediately after any packet receive operation
Example Usage:
if (packet.Validate()) {
// Safe to process packet data
ProcessPacketData(packet);
} else {
// Discard corrupted packet
printf("Invalid packet received\r\n");
}

The documentation for this class was generated from the following file: