1 /* $Id: buffer.c 7285 2005-06-07 06:38:24Z eagle $
3 ** The Buffer class for innfeed.
5 ** Written by James Brister <brister@vix.com>
7 ** The implementation of the Buffer class. Buffers are reference counted
8 ** objects that abstract memory regions in a way similar to struct iovec.
16 #include "inn/messages.h"
22 static Buffer gBufferList = NULL ;
23 static Buffer bufferPool = NULL ;
24 static unsigned int bufferCount = 0 ;
25 static unsigned int bufferByteCount = 0 ;
32 size_t memSize ; /* the length of mem */
33 size_t dataSize ; /* amount that has actual data in it. */
35 void (*bufferDeletedCbk)(void *);
36 void *bufferDeletedCbkData;
37 struct buffer_s *next ;
38 struct buffer_s *prev ;
41 #define BUFFER_POOL_SIZE ((4096 - 2 * (sizeof (void *))) / (sizeof (struct buffer_s)))
43 static void fillBufferPool (void)
47 bufferPool = xmalloc (sizeof(struct buffer_s) * BUFFER_POOL_SIZE) ;
49 for (i = 0; i < BUFFER_POOL_SIZE - 1; i++)
50 bufferPool[i] . next = &(bufferPool [i + 1]) ;
51 bufferPool [BUFFER_POOL_SIZE-1] . next = NULL ;
55 Buffer newBuffer (size_t size)
59 if (bufferPool == NULL)
64 bufferPool = bufferPool->next ;
68 nb->mem = xmalloc (size + 1) ;
70 nb->mem [size] = '\0' ;
73 nb->deletable = true ;
74 nb->bufferDeletedCbk = NULL;
75 nb->bufferDeletedCbkData = NULL;
77 bufferByteCount += size + 1 ;
80 nb->next = gBufferList ;
82 if (gBufferList != NULL)
83 gBufferList->prev = nb ;
87 d_printf (1,"Creating a DELETABLE buffer %p\n",nb) ;
94 Buffer newBufferByCharP (const char *ptr, size_t size, size_t dataSize)
98 if (bufferPool == NULL)
102 ASSERT (nb != NULL) ;
103 bufferPool = bufferPool->next ;
106 nb->mem = (char *) ptr ; /* cast away const */
108 nb->dataSize = dataSize ;
109 nb->deletable = false ;
110 nb->bufferDeletedCbk = NULL;
111 nb->bufferDeletedCbkData = NULL;
113 nb->next = gBufferList ;
115 if (gBufferList != NULL)
116 gBufferList->prev = nb ;
121 d_printf (1,"Creating a NON-DELETABLE buffer %p\n",nb) ;
128 void delBuffer (Buffer buff)
130 if (buff != NULL && --(buff->refCount) == 0)
133 d_printf (1,"Freeing a %s buffer (%p)\n",
134 (buff->deletable ? "DELETABLE" : "NON-DELETABLE"), buff) ;
140 bufferByteCount -= (buff->memSize + 1) ;
145 if (buff->bufferDeletedCbk) {
146 (buff->bufferDeletedCbk)(buff->bufferDeletedCbkData);
147 buff->bufferDeletedCbk = NULL;
148 buff->bufferDeletedCbkData = NULL;
151 if (buff->next != NULL)
152 buff->next->prev = buff->prev ;
153 if (buff->prev != NULL)
154 buff->prev->next = buff->next ;
157 ASSERT(gBufferList == buff) ;
158 gBufferList = buff->next ;
161 buff->next = bufferPool ;
166 Buffer bufferTakeRef (Buffer buff)
168 ASSERT (buff != NULL) ;
177 void gPrintBufferInfo (FILE *fp, unsigned int indentAmt)
180 char indent [INDENT_BUFFER_SIZE] ;
183 for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
187 fprintf (fp,"%sGlobal Buffer List : (count %d) {\n",indent,bufferCount) ;
189 for (b = gBufferList ; b != NULL ; b = b->next)
190 printBufferInfo (b,fp,indentAmt + INDENT_INCR) ;
192 fprintf (fp,"%s}\n",indent) ;
195 void printBufferInfo (Buffer buffer, FILE *fp, unsigned int indentAmt)
197 char indent [INDENT_BUFFER_SIZE] ;
198 char bufferStart [256] ;
201 for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
205 fprintf (fp,"%sBuffer : %p {\n",indent,(void *) buffer) ;
209 fprintf (fp,"%s}\n",indent) ;
213 i = MIN(sizeof (bufferStart) - 1,buffer->dataSize) ;
214 memcpy (bufferStart,buffer->mem,i) ;
215 bufferStart[i] = '\0';
217 fprintf (fp,"%s refcount : %d\n",indent,buffer->refCount) ;
218 fprintf (fp,"%s data-size : %ld\n",indent,(long) buffer->dataSize) ;
219 fprintf (fp,"%s mem-size : %ld\n",indent,(long) buffer->memSize) ;
220 fprintf (fp,"%s base : %p\n", indent,(void *) buffer->mem) ;
221 fprintf (fp,"%s deletable : %s\n",indent,boolToString(buffer->deletable));
222 fprintf (fp,"%s buffer [0:%ld] : \"%s\"\n",
223 indent, (long) i, bufferStart) ;
224 fprintf (fp,"%s}\n",indent) ;
228 void *bufferBase (Buffer buff)
233 size_t bufferSize (Buffer buff)
235 return buff->memSize ;
238 size_t bufferDataSize (Buffer buff)
240 return buff->dataSize ;
243 void bufferIncrDataSize (Buffer buff, size_t size)
245 if (buff->dataSize + size > buff->memSize)
246 die ("Trying to make a buffer data size bigger than its memory alloc");
248 buff->dataSize += size ;
251 void bufferDecrDataSize (Buffer buff, size_t size)
253 ASSERT (size > buff->dataSize) ;
255 buff->dataSize -= size ;
258 void bufferSetDataSize (Buffer buff, size_t size)
260 buff->dataSize = size ;
262 ASSERT (buff->dataSize <= buff->memSize) ;
265 void bufferSetDeletedCbk (Buffer buff, void (*cbk)(void *), void *data)
267 ASSERT(buff->bufferDeletedCbk == NULL &&
268 buff->bufferDeletedCbk != cbk);
269 ASSERT(buff->bufferDeletedCbkData == NULL &&
270 buff->bufferDeletedCbkData != data);
271 buff->bufferDeletedCbk = cbk;
272 buff->bufferDeletedCbkData = data;
275 void freeBufferArray (Buffer *buffs)
290 /* Allocate an array and put all the arguments (the last of which must be
291 NULL) into it. The terminating NULL is put in the returned array. */
292 Buffer *makeBufferArray (Buffer buff, ...)
295 size_t cLen = 10, idx = 0 ;
298 ptr = xcalloc (cLen, sizeof(Buffer)) ;
302 va_start (ap, buff) ;
305 p = va_arg (ap, Buffer) ;
309 ptr = xrealloc (ptr, sizeof(Buffer) * cLen) ;
320 bool isDeletable (Buffer buff)
322 return buff->deletable ;
327 /* Dups the array including taking out references on the Buffers inside */
328 Buffer *dupBufferArray (Buffer *array)
333 while (array && array [count] != NULL)
336 newArr = xmalloc (sizeof(Buffer) * (count + 1)) ;
338 for (count = 0 ; array [count] != NULL ; count++)
339 newArr [count] = bufferTakeRef (array [count]) ;
341 newArr [count] = NULL ;
347 unsigned int bufferArrayLen (Buffer *array)
349 unsigned int count = 0 ;
352 while (*array != NULL)
362 bool copyBuffer (Buffer dest, Buffer src)
364 char *baseDest = bufferBase (dest) ;
365 char *baseSrc = bufferBase (src) ;
366 unsigned int amt = bufferDataSize (src) ;
368 if (amt > bufferSize (dest))
371 memcpy (baseDest, baseSrc, amt) ;
373 bufferSetDataSize (dest,amt) ;
379 unsigned int bufferRefCount (Buffer buf)
381 return buf->refCount ;
385 void bufferAddNullByte (Buffer buff)
387 char *p = bufferBase (buff) ;
389 p [buff->dataSize] = '\0' ;
393 /* append the src buffer to the dest buffer growing the dest as needed.
394 Can only be done to deletable buffers. */
395 bool concatBuffer (Buffer dest, Buffer src)
397 ASSERT (dest->deletable) ;
399 if ( !dest->deletable )
400 return false ; /* yeah, i know this is taken care of above */
402 if ((dest->dataSize + src->dataSize) > dest->memSize)
404 char *newMem = xcalloc (dest->dataSize + src->dataSize + 1, 1) ;
406 bufferByteCount += ((dest->dataSize + src->dataSize) - dest->memSize) ;
408 memcpy (newMem, dest->mem, dest->dataSize) ;
410 ASSERT (dest->mem != NULL) ;
414 dest->memSize = dest->dataSize + src->dataSize ; /* yep. 1 less */
417 memcpy (&dest->mem[dest->dataSize], src->mem, dest->dataSize) ;
419 dest->dataSize += src->dataSize ;
425 /* realloc the buffer's memory to increase the size by AMT */
426 bool expandBuffer (Buffer buff, size_t amt)
428 d_printf (2,"Expanding buffer....\n") ;
430 if (!buff->deletable)
433 bufferByteCount += amt ;
434 buff->memSize += amt ;
436 buff->mem = xrealloc (buff->mem, buff->memSize + 1) ;
442 /* Take a buffer and shift the contents around to add the necessary CR
443 before every line feed and a '.' before every '.' at the start of a
445 bool nntpPrepareBuffer (Buffer buffer)
447 int msize, newDsize, dsize, extra ;
448 char *base, p, *src, *dst ;
449 bool needfinal = false ;
451 ASSERT (buffer != NULL) ;
453 dsize = buffer->dataSize ;
454 msize = buffer->memSize - 1 ;
459 for (src = base + dsize - 1 ; src > base ; )
476 if (dsize > 0 && base [dsize - 1] != '\n')
482 newDsize = dsize + extra ;
484 if (msize - dsize < extra)
486 d_printf (2,"Expanding buffer in nntpPrepareBuffer (from %d to %d)\n",
487 msize, msize + (extra - (msize - dsize))) ;
489 if ( !expandBuffer (buffer, extra - (msize - dsize)) )
491 d_printf (1,"Expand failed...\n") ;
495 ASSERT (dsize == (int) buffer->dataSize) ;
500 base [newDsize] = '\0' ;
501 base [newDsize - 1] = '\n' ;
502 base [newDsize - 2] = '\r' ;
503 base [newDsize - 3] = '.' ;
509 base [newDsize - 1] = '\n' ;
510 base [newDsize - 2] = '\r' ;
518 src = base + dsize - 1 ;
519 dst = base + newDsize - 1 ;
538 p = *dst-- = *src-- ;
540 ASSERT(dst >= base && src >= base) ;
547 bufferSetDataSize (buffer,newDsize) ;