nbuffer.c File Reference

Network buffer management: Implementation More...

#include "..\includes.h"
#include "nbuffer.h"

Macros

#define MAX_NBUFFER_SIZE
 
#define NBUFFER_NO_ERROR   NBufferMessages[0]
 
#define NBUFFER_OUT_OF_MEMORY_ERROR   NBufferMessages[1]
 

Functions

char * NBufferAcquireBuffer (SOCKET *so)
 acquire new buffer More...
 
int NBufferFreeBuffer (SOCKET *so)
 free packet buffer More...
 

Variables

const char * NBufferMessages []
 

Detailed Description

                          _         _             _
                       __| |    ___(_) ____ _ __ | |_
                      / _` |   / __| |/ _` | '_ \| __|
                     | (_| | _ \__ \ | (_| | | | | |_
                      \__,_|(_) ___/_|\__, |_| |_|\__|
                     Signalprocessing |___/ Technology
Author
D.SignT GmbH & Co. KG, Claus Hermbusche
Version
2.91
Date
2019-04-17

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.

Per multi buffered socket two structures must be created in the user application. This is the main data buffer (NBuffer_t) and the buffer control structure (NBCtl_t).

E.g.:

#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
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 you 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 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


Macro Definition Documentation

#define MAX_NBUFFER_SIZE
Examples:
Echo.c.
#define NBUFFER_NO_ERROR   NBufferMessages[0]
#define NBUFFER_OUT_OF_MEMORY_ERROR   NBufferMessages[1]

Function Documentation

char* NBufferAcquireBuffer ( SOCKET *  so)

[Network Buffer Control Structure]

Parameters
so- socket to acquire new buffer for
Returns
buffer if successful, NULL if no buffer available
Note
Precondition is a valid user_pointer to a buffer control structure
257 {
258  /***************************************************************************
259  locals
260  ***************************************************************************/
261  NBCtl_t *bctl = (NBCtl_t *)so-> user_pointer; /* get buffer control */
262  size_t psize;
263  char *pbuffer;
264 
265  if ( bctl == NULL )
266  {
267  /***********************************************************************
268  no control structure available
269  ***********************************************************************/
270  return (NULL);
271  } // if
272 
273  /***************************************************************************
274  check used buffers
275  ***************************************************************************/
276  if ( bctl-> BuffersInUse >= bctl-> MaxBuffers )
277  {
278  /***********************************************************************
279  all buffers in use
280  ***********************************************************************/
281  return (NULL);
282  } // if
283 
284  /***************************************************************************
285  check receive index range
286  ***************************************************************************/
287  if ( ++bctl-> ri >= bctl-> MaxBuffers )
288  {
289  /***********************************************************************
290  wrap around ring buffer
291  ***********************************************************************/
292  bctl-> ri = 0;
293  } // if
294 
295  /***************************************************************************
296  depending on protocol allocate max packet size
297  ***************************************************************************/
298  psize = (so-> proto == IPT_TCP)? TCP_MAX_PACKET_SIZE* sizeof(char)
299  : UDP_MAX_PACKET_SIZE* sizeof(char);
300 
301  /***************************************************************************
302  limit to buffer size
303  ***************************************************************************/
304  if ( psize > bctl-> NBuffer_SizeLimit )
305  {
306  psize = bctl-> NBuffer_SizeLimit;
307  } // if
308 
309 
310  /***************************************************************************
311  use dynamic memory?
312  ***************************************************************************/
313  if ( bctl-> UseDynMem )
314  {
315  /***********************************************************************
316  allocate a new buffer
317  ***********************************************************************/
318  pbuffer = bctl-> Buf[bctl-> ri].Data = (char *) malloc (psize*2);
319  if ( pbuffer == NULL )
320  {
322  }
323  }
324  else
325  {
326  /***********************************************************************
327  for static buffers determine next buffer offset
328  from nubffer.c view NBuffer_t member Data is a simple char * not an
329  array of char, because define USE_STATIC_MEMORY is undefined (defined
330  in user application). Thus we cannot use bctl-> buf[bctl-> ri].Data
331  here and have to calculate the new buffer offset manually
332  ***********************************************************************/
333  pbuffer = (char *)((uint32_t)(bctl-> Buf) + (bctl-> ri * bctl-> NBuffer_tsize));
334  }
335 
336  /***************************************************************************
337  assign new buffer to socket
338  for TCP this buffer size (psize in this case) is offered to peer as
339  TCP Window Size
340  ***************************************************************************/
341  set_recv_buffer (so, pbuffer, (uint16_t)psize );
342 
343  //~ CPrintf ("allocate: %08lx\r\n", buffer);
344 
345  /***************************************************************************
346  maintain buffer counter
347  ***************************************************************************/
348  bctl-> BuffersInUse++;
349 
350  return (pbuffer);
351 }
#define prg_exit(s)
Definition: Common.h:267
int32_t set_recv_buffer(SOCKET *so, void *data, uint16_t maxdatasize)
Define a socket buffer.
if(RecentEpoch.tv_usec >=1000000)
Definition: timer.c:124
#define IPT_TCP
Definition: net.h:496
#define NULL
Definition: net.h:126
unsigned short uint16_t
Definition: stdint.h:45
#define TCP_MAX_PACKET_SIZE
Definition: net.h:681
Network Buffer Control Structure.
Definition: nbuffer.h:108
unsigned int uint32_t
Definition: stdint.h:47
#define UDP_MAX_PACKET_SIZE
Definition: net.h:671
#define NBUFFER_OUT_OF_MEMORY_ERROR
int NBufferFreeBuffer ( SOCKET *  so)
Parameters
so- socket to release old buffer
Returns
  • 0 - success
  • -1 - error
Note
Precondition is a valid user_pointer to a buffer control structure
365 {
366  /***************************************************************************
367  locals
368  ***************************************************************************/
369  NBCtl_t *bctl = (NBCtl_t *)so-> user_pointer; /* get buffer control */
370  char *pbuffer;
371 
372  if ( bctl == NULL )
373  {
374  /***********************************************************************
375  no control structure available
376  ***********************************************************************/
377  return (-1);
378  } // if
379 
380  /***************************************************************************
381  range check
382  ***************************************************************************/
383  if (( bctl-> pi != BUFFER_EMPTY ) && ( bctl-> pi < bctl-> MaxBuffers ) )
384  {
385  /***********************************************************************
386  use dynamic memory?
387  ***********************************************************************/
388  if ( bctl-> UseDynMem )
389  {
390  pbuffer = bctl-> Buf[bctl-> pi].Data;
391  //~ CPrintf ("free: %08lx\r\n", buffer);
392 
393  /*******************************************************************
394  free memory
395  *******************************************************************/
396  free ((void *)pbuffer );
397  }
398  else
399  {
400  /*******************************************************************
401  for static buffers determine next buffer offset
402  from nubffer.c view NBuffer_t member Data is a simple char * not an
403  array of char, because define USE_STATIC_MEMORY is undefined (defined
404  in user application). Thus we cannot use bctl-> Buf[bctl-> ri].Data
405  here.
406  *******************************************************************/
407  pbuffer = (char *)((uint32_t)(bctl-> Buf) + (bctl-> pi * bctl-> NBuffer_tsize));
408  }
409 
410  //~ CPrintf ("free: %08lx\r\n", buffer);
411 
412  /***********************************************************************
413  maintain buffer counter
414  ***********************************************************************/
415  bctl-> BuffersInUse--;
416  } // if
417 
418  /***************************************************************************
419  maintain process index
420  ***************************************************************************/
421  if ( ++bctl-> pi >= bctl-> MaxBuffers )
422  {
423  /***********************************************************************
424  wrap around ring buffer
425  ***********************************************************************/
426  bctl-> pi = 0;
427  } // if
428 
429  /***************************************************************************
430  was it the last buffer (process index points to receive index)?
431  ***************************************************************************/
432  if ( bctl-> pi == bctl-> ri )
433  {
434  /***********************************************************************
435  yes, set buffer empty flag
436  ***********************************************************************/
437  bctl-> pi = BUFFER_EMPTY;
438  } // if
439 
440  return (0);
441 }
if(RecentEpoch.tv_usec >=1000000)
Definition: timer.c:124
#define NULL
Definition: net.h:126
Network Buffer Control Structure.
Definition: nbuffer.h:108
unsigned int uint32_t
Definition: stdint.h:47
#define BUFFER_EMPTY
Definition: nbuffer.h:72

Variable Documentation

const char* NBufferMessages[]
Initial value:
= {
"",
#define NBUFFER_NO_ERROR
"out of memory error"
#define NBUFFER_OUT_OF_MEMORY_ERROR
}