Network Buffer Management

Description

Network buffer management. This module simplifies the use of multiple data buffers for sockets. Each socket gets its own buffer control structure and multiple buffers (e.g. for ping-pong-buffering) organized as ring buffers.

The buffers can be allocated dynamically or defined statically. A define USE_STATIC_MEMORY forces this module to select the desired memory usage.


Data Structures

Per multi buffered socket two structures must be created in the user application. This is the main data buffer

typedef struct
{
/***********************************************************************//**
pointer to buffer
***************************************************************************/
#ifdef USE_STATIC_MEMORY
char Data[MAX_NBUFFER_SIZE*2];
#else
char *Data;
#endif
/***********************************************************************//**
size of valid data in buffer
***************************************************************************/
uint32_t Size;

and the buffer control structure

typedef struct
{
/***********************************************************************//**
buffers
***************************************************************************/
NBuffer_t *Buf;
/***********************************************************************//**
size of NBuffer_t for static memory offset calculation
***************************************************************************/
uint32_t NBuffer_tsize;
/***********************************************************************//**
count used buffers
***************************************************************************/
int16_t BuffersInUse;
/***********************************************************************//**
out of buffer flag
***************************************************************************/
int16_t OutOfBuffer;
/***********************************************************************//**
receive index
***************************************************************************/
int16_t ri;
/***********************************************************************//**
process index
***************************************************************************/
int16_t pi;
/***********************************************************************//**
max buffers
***************************************************************************/
int16_t MaxBuffers;
/***********************************************************************//**
use dynamic memory
***************************************************************************/
int16_t UseDynMem;
/***********************************************************************//**
NBuffer size limit
***************************************************************************/
uint32_t NBuffer_SizeLimit;




Example

Refer to NetTest.c example or Echo.c example

E.g.:

#define USE_STATIC_MEMORY TRUE
#define MAX_NBUFFER_SIZE (1500)
#include "..\..\..\Common\nbuffer.h" // network buffer support
#define MAX_UDP_BUFFERS 4
// main data buffer
NBuffer_t udp_buffer[MAX_UDP_BUFFERS]; // buffers for UDP echo
// create and pre-initialize buffer control structure
{
udp_buffer, // buffers (defined before)
sizeof(NBuffer_t), // size of NBuffer_t
0, // used buffers
0, // out of buffer memory
BUFFER_EMPTY, // receive index
BUFFER_EMPTY, // process index
MAX_UDP_BUFFERS, // max buffers
0, // use static memory
#else
1, // use dynamic memory
#endif
MAX_NBUFFER_SIZE // NBuffer size limit
};


After allocating a socket with socket_open(), the buffer control structure must be assigned to this socket

// *************************************************************************
// attach buffer control structure to socket
// (required for NBufferAcquireBuffer() later)
// *************************************************************************
udp_echo_so-> user_pointer = &bcontrol;


Initially NBufferAcquireBuffer() must be called for this socket to get a new buffer assigned to this socket:

// *************************************************************************
// initially malloc space for data
// NBufferAcquireBuffer() allocates new buffer space and modifies the
// bcontrol structure
// *************************************************************************
{
prg_exit ("out of memory error");
} // if


After receiving new data (net_recv() returns a value > 0 or a callback function is called with new data), the user can decide if this buffer can be processed immediately and re-used for the next incoming data or if the packet must be processed later. In the latter case the current buffer index for later processing can be stored to

bctl-> pi

and a new function call to

will allocate and attach the next buffer.

If a buffer is waiting for processing, can be detected in your application by testing

NBCtl_t *bctl = (NBCtl_t *)so-> user_pointer; // get buffer control
if ( bctl-> pi != BUFFER_EMPTY ) ...


After processing the cached data, this buffer must be freed with

This function call maintains the process index pi and sets BUFFER_EMPTY, if process index points to receive index.


Error Handling

Error handling for UDP and for TCP is a bit different. For both protocols a flag OutOfBuffer must be set immediately when function NBufferAcquireBuffer() returns no buffer. For TCP additionally a zero window packet must be sent to avoid a buffer overrun when the peer sends the next packet

{
// ***************************************************************
// allocation failed due to all buffers in use.
// this may happen when the receive task works faster than the
// signal processing task.
// send a zero window packet to the remote side to stop the TCP
// and set OutOfBuffer flag to handle this condition later
// ***************************************************************
bctl-> OutOfBuffer = TRUE;
tcp_send_zero_window ( so ); // for TCP only
} // if


In the main network task (this is where your net_isq() is called frequently) check the OutOfBuffer condition and try to allocate a new buffer

if ( bctl-> OutOfBuffer )
{
if ( NBufferAcquireBuffer (so) != NULL )
{
// *******************************************************************
// allocation successful,
// reset OutOfBuffer flag,
// send window update to start the TCP
// *******************************************************************
bctl-> OutOfBuffer = FALSE;
tcp_send_window_update ( so ); // for TCP only
} // if
} // if