📄 netbuf.c
字号:
/*****************************************************************************
* netbuf.c - Network Buffers program file.
*
* Copyright (c) 1998 by Global Election Systems Inc. All rights reserved.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 98-01-30 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original based on BSD codes.
******************************************************************************
* PROGRAMMER NOTES
*
* FREE BUFFER MARK
* Free buffers have nextChain pointing back to themselves.
*
* CRITICAL SECTIONS
* Only queue operations are protected from corruption from other tasks and
* interrupts. It is assumed that only one task at a time operates on a buffer
* chain but multiple tasks will share queues.
*
* BUFFER QUEUES
* The buffer queue structure's primary purpose is to minimize the overhead
* of adding a new chain to the queue. A side benefit is that if packets
* span more than one nBuf, then the overhead to seek to a particular offset
* in the queue is reduced. A queue is required to maintain boundaries of
* incoming UDP datagrams if UDP support were added.
*****************************************************************************/
#include "typedefs.h"
#include "avconfig.h"
#include "string.h"
#include "stdio.h" // Required by debug.h
#include "avos.h"
#include "netbuf.h"
#include "debug.h"
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
#define MAXNBUFS 32 /* The number of nBufs allocated. */
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
NBuf *topNBuf;
#if STATS_SUPPORT > 0
NBufStats nBufStats;
#else
u_int curFreeBufs;
#endif
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
/* The free list of buffers. */
static NBuf nBufs[MAXNBUFS];
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/* Initialize the memory buffer subsytem. */
void nBufInit (void)
{
int i;
topNBuf = &nBufs[0];
for (i = 0; i < MAXNBUFS; i++) {
nBufs[i].nextBuf = &nBufs[i + 1];
nBufs[i].nextChain = &nBufs[i];
}
nBufs[MAXNBUFS - 1].nextBuf = NULL;
#if STATS_SUPPORT > 0
memset(&nBufStats, 0, sizeof(nBufStats));
nBufStats.headLine.fmtStr = "\t\tNETWORK BUFFERS\r\n";
nBufStats.curFreeBufs.fmtStr = "\tCURRENT FREE: %5lu\r\n";
nBufStats.curFreeBufs.val = MAXNBUFS;
nBufStats.minFreeBufs.fmtStr = "\tMINIMUM FREE: %5lu\r\n";
nBufStats.minFreeBufs.val = MAXNBUFS;
nBufStats.maxFreeBufs.fmtStr = "\tMAXIMUM FREE: %5lu\r\n";
nBufStats.maxFreeBufs.val = MAXNBUFS;
nBufStats.maxChainLen.fmtStr = "\tMAX CHAIN SZ: %5lu\r\n";
#else
curFreeBufs = MAXNBUFS;
#endif
}
/*
* nFree - Free a single nBuf and associated external storage.
* Return the next nBuf in the chain, if any.
*/
NBuf *nFree(NBuf *n)
{
NBuf *n0;
nFREE(n, n0)
return n0;
}
/*
* nFreeChain - Free all nBufs in a chain.
* Return the next chain in the queue, if any.
*/
NBuf *nFreeChain(NBuf *n)
{
NBuf *n0, *n1;
if (n) {
if (n->nextChain == n)
panic("nFreeChain");
else {
n0 = n;
n = n->nextChain;
while (n0) {
nFREE(n0, n1);
n0 = n1;
}
}
}
return n;
}
/*
* nPrepend - Prepend plen bytes to nBuf n and load from s if non-null.
* A new nBuf is always allocated but if allocation fails, the
* original nBuf chain is freed. The chain size is updated. This assumes
* that the chain is not in a queue.
* Return the new nBuf chain on success, NULL on failure.
*/
NBuf *nPrepend(
NBuf *n, /* Destination nBuf chain. */
const char *s, /* The data to prepend. */
u_int plen /* The length of the data to prepend. */
)
{
NBuf *n0;
if (n) {
nGET(n0);
while (n0) {
n0->nextBuf = n;
if (plen > NBUFSZ) {
n0->len = NBUFSZ;
#if STATS_SUPPORT > 0
if ((n0->chainLen = n->chainLen + NBUFSZ) > nBufStats.maxChainLen.val)
nBufStats.maxChainLen.val = n0->chainLen;
#else
n0->chainLen = n->chainLen + NBUFSZ;
#endif
if (s) {
memcpy(n0->data, s + plen - NBUFSZ, NBUFSZ);
}
plen -= NBUFSZ;
n = n0;
nGET(n0);
} else {
n0->len = plen;
#if STATS_SUPPORT > 0
if ((n0->chainLen = n->chainLen + plen) > nBufStats.maxChainLen.val)
nBufStats.maxChainLen.val = n0->chainLen;
#else
n0->chainLen = n->chainLen + plen;
#endif
n0->data = n0->body + NBUFSZ - plen;
if (s) {
memcpy(n0->data, s, plen);
}
plen = 0;
n = n0;
/*** We're done, skip the test.
n0 = NULL;
***/
break;
}
}
if (plen) {
NBUFDEBUG((LOG_ERR, "nPrepend: No free buffers"));
(void)nFreeChain(n);
n = NULL;
}
}
return n;
}
/*
* nAppend - Append slen bytes to the nBuf chain n and load from s if non-null.
* Note that the chain length is updated but the chain is assumed to not be in
* a queue.
* Return the number of bytes appended.
*/
u_int nAppend(NBuf *n, const char *s, u_int sLen)
{
u_int copied = 0, i;
NBuf *n0 = n;
if (n0 && sLen) {
/* Find the last nBuf on the chain. */
for (; n0->nextBuf; n0 = n0->nextBuf);
/* If there's space, append what we can. */
if ((i = (u_int)nTRAILINGSPACE(n0)) > 0) {
if (i > sLen)
i = sLen;
n0->len += i;
#if STATS_SUPPORT > 0
if ((n->chainLen += i) > nBufStats.maxChainLen.val)
nBufStats.maxChainLen.val = n->chainLen;
#else
n->chainLen += i;
#endif
if (s) {
memcpy(n0->data, s, i);
s += i;
}
copied = i;
sLen -= i;
}
if (sLen) {
nGET(n0->nextBuf);
n0 = n0->nextBuf;
}
}
/* Append new buffers until s is consumed or we fail to allocate. */
while (n0 && sLen) {
if (sLen > NBUFSZ) {
n0->len = NBUFSZ;
#if STATS_SUPPORT > 0
if ((n->chainLen += NBUFSZ) > nBufStats.maxChainLen.val)
nBufStats.maxChainLen.val = n->chainLen;
#else
n->chainLen += NBUFSZ;
#endif
if (s) {
memcpy(n0->data, s, NBUFSZ);
s += NBUFSZ;
}
sLen -= NBUFSZ;
copied += NBUFSZ;
} else {
n0->len = sLen;
#if STATS_SUPPORT > 0
if ((n->chainLen += sLen) > nBufStats.maxChainLen.val)
nBufStats.maxChainLen.val = n->chainLen;
#else
n->chainLen += sLen;
#endif
if (s) {
memcpy(n0->data, s, sLen);
}
copied += sLen;
break; /* We're done, skip the test. */
}
nGET(n0->nextBuf);
n0 = n0->nextBuf;
}
return copied;
}
/*
* nAppendBuf - Append data from buffer chain n1 starting from the offset
* onto the end of the chain n0.
* Return the number of characters appended.
*/
u_int nAppendBuf(
NBuf *nDst, /* The destination chain. */
NBuf *nSrc, /* The source chain. */
u_int off0, /* The starting offset into the source. */
u_int len /* The maximum bytes to copy. */
)
{
u_int st = 0, copySz;
NBuf *nTop = nDst, *nTmp;
if (!nDst)
return 0;
/* Find the end of the destination chain. */
nTop = nDst;
for (; nDst->nextBuf; nDst = nDst->nextBuf)
;
/* Find the starting position in the source chain. */
for (; nSrc && off0 > nSrc->len; nSrc = nSrc->nextBuf)
off0 -= nSrc->len;
if (nSrc) {
while (nDst && len) {
/* Compute how much to copy from the current source buffer. */
copySz = min(len, nSrc->len - off0);
/* Do we need to append another destination buffer? */
/*
* Note that we don't attempt to fill small spaces at the
* end of the current destination buffer since on average,
* we don't expect that it would reduce the number of
* buffers used and it would complicate and slow the
* operation.
*/
if (nTRAILINGSPACE(nDst) < copySz) {
nGET(nTmp);
if (!nTmp) {
NBUFDEBUG((LOG_ERR, "nBufCopy: No free buffers"));
nDst = NULL;
break;
}
nDst->nextBuf = nTmp;
nDst = nTmp;
}
/* Copy it and advance to the next source buffer if needed. */
memcpy(&nDst->data[nDst->len], &nSrc->data[off0], copySz);
#if STATS_SUPPORT > 0
if ((nTop->chainLen += copySz) > nBufStats.maxChainLen.val)
nBufStats.maxChainLen.val = nTop->chainLen;
#else
nTop->chainLen += copySz;
#endif
nDst->len += copySz;
st += copySz;
len -= copySz;
off0 = 0;
nSrc = nSrc->nextBuf;
}
}
return st;
}
/*
* nAppendFromQ - Append data from a source queue starting from the offset
* onto the end of the destination chain.
* Return the number of characters appended.
*/
u_int nAppendFromQ(
NBuf *nDst, /* The destination chain. */
NBufQHdr *nSrcQ, /* The source queue. */
u_int off0, /* The starting offset into the source. */
u_int len /* The maximum bytes to copy. */
)
{
u_int st = 0, copySz;
NBuf *nDstTop, *nSrc, *nSrcTop, *nTmp;
/* Validate parameters. */
if (!nDst || !nSrcQ)
return 0;
/* Find the end of the destination chain. */
nDstTop = nDst;
while (nDst->nextBuf)
nDst = nDst->nextBuf;
/* Find the starting chain in the source queue. */
for (nSrc = nSrcQ->qHead; nSrc && off0 >= nSrc->chainLen; nSrc = nSrc->nextChain) {
off0 -= nSrc->chainLen;
}
nSrcTop = nSrc;
/* Find the starting position in the source chain. */
for (; nSrc && off0 >= nSrc->len; nSrc = nSrc->nextBuf) {
off0 -= nSrc->len;
}
while (nSrc && nDst && len) {
/*
* Compute how much to copy from the current source buffer.
* Note that since we copy from a single source buffer at a
* time, we don't have to check that the copy size fits in
* a single buffer.
*/
copySz = min(len, nSrc->len - off0);
/* Append another destination buffer if needed. */
/*
* Note that we don't attempt to fill small spaces at the
* end of the current destination buffer since on average,
* we don't expect that it would reduce the number of
* buffers used and it would complicate and slow the
* operation.
*/
if (nTRAILINGSPACE(nDst) < copySz) {
nGET(nTmp);
if (!nTmp) {
NBUFDEBUG((LOG_ERR, "nAppendFromQ: No free buffers"));
nDst = NULL;
break;
}
nDst->nextBuf = nTmp;
nDst = nTmp;
}
/* Copy it and advance to the next source buffer if needed. */
memcpy(&nDst->data[nDst->len], &nSrc->data[off0], copySz);
#if STATS_SUPPORT > 0
if ((nDstTop->chainLen += copySz) > nBufStats.maxChainLen.val)
nBufStats.maxChainLen.val = nDstTop->chainLen;
#else
nDstTop->chainLen += copySz;
#endif
nDst->len += copySz;
st += copySz;
len -= copySz;
off0 = 0;
if ((nSrc = nSrc->nextBuf) == NULL)
nSrc = nSrcTop = nSrcTop->nextChain;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -