2 * IRC - Internet Relay Chat, common/dbuf.c
3 * Copyright (C) 1990 Markku Savela
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 1, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "ircd_alloc.h"
23 #include "ircd_chattr.h"
24 #include "ircd_features.h"
26 #include "sys.h" /* MIN */
32 * dbuf is a collection of functions which can be used to
33 * maintain a dynamic buffering of a byte stream.
34 * Functions allocate and release memory dynamically as
35 * required [Actually, there is nothing that prevents
36 * this package maintaining the buffer on disk, either]
39 int DBufAllocCount = 0;
40 int DBufUsedCount = 0;
42 static struct DBufBuffer *dbufFreeList = 0;
44 #define DBUF_SIZE 2048
47 struct DBufBuffer *next; /* Next data buffer, NULL if last */
48 char *start; /* data starts here */
49 char *end; /* data ends here */
50 char data[DBUF_SIZE]; /* Actual data stored here */
53 void dbuf_count_memory(size_t *allocated, size_t *used)
55 assert(0 != allocated);
57 *allocated = DBufAllocCount * sizeof(struct DBufBuffer);
58 *used = DBufUsedCount * sizeof(struct DBufBuffer);
62 * dbuf_alloc - allocates a DBufBuffer structure from the free list or
65 static struct DBufBuffer *dbuf_alloc(void)
67 struct DBufBuffer* db = dbufFreeList;
70 dbufFreeList = db->next;
73 else if (DBufAllocCount * DBUF_SIZE < feature_int(FEAT_BUFFERPOOL)) {
74 db = (struct DBufBuffer*) MyMalloc(sizeof(struct DBufBuffer));
83 * dbuf_free - return a struct DBufBuffer structure to the freelist
85 static void dbuf_free(struct DBufBuffer *db)
89 db->next = dbufFreeList;
94 * This is called when malloc fails. Scrap the whole content
95 * of dynamic buffer. (malloc errors are FATAL, there is no
96 * reason to continue this buffer...).
97 * After this the "dbuf" has consistent EMPTY status.
99 static int dbuf_malloc_error(struct DBuf *dyn)
101 struct DBufBuffer *db;
102 struct DBufBuffer *next;
104 for (db = dyn->head; db; db = next)
109 dyn->tail = dyn->head = 0;
115 * dbuf_put - Append the number of bytes to the buffer, allocating memory
116 * as needed. Bytes are copied into internal buffers from users buffer.
118 * Returns > 0, if operation successful
119 * < 0, if failed (due memory allocation problem)
121 * dyn: Dynamic buffer header
122 * buf: Pointer to data to be stored
123 * length: Number of bytes to store
125 int dbuf_put(struct DBuf *dyn, const char *buf, unsigned int length)
127 struct DBufBuffer** h;
128 struct DBufBuffer* db;
134 * Locate the last non-empty buffer. If the last buffer is full,
135 * the loop will terminate with 'db==NULL'.
136 * This loop assumes that the 'dyn->length' field is correctly
137 * maintained, as it should--no other check really needed.
144 * Append users data to buffer, allocating buffers as needed
146 dyn->length += length;
148 for (; length > 0; h = &(db->next)) {
149 if (0 == (db = *h)) {
150 if (0 == (db = dbuf_alloc())) {
151 if (feature_bool(FEAT_HAS_FERGUSON_FLUSHER)) {
153 * from "Married With Children" episode were Al bought a REAL toilet
154 * on the black market because he was tired of the wimpy water
155 * conserving toilets they make these days --Bleep
158 * Apparently this doesn't work, the server _has_ to
159 * dump a few clients to handle the load. A fully loaded
160 * server cannot handle a net break without dumping some
161 * clients. If we flush the connections here under a full
162 * load we may end up starving the kernel for mbufs and
166 * attempt to recover from buffer starvation before
167 * bailing this may help servers running out of memory
169 flush_connections(0);
174 return dbuf_malloc_error(dyn);
179 db->start = db->end = db->data;
181 chunk = (db->data + DBUF_SIZE) - db->end;
186 memcpy(db->end, buf, chunk);
197 * dbuf_map, dbuf_delete
199 * These functions are meant to be used in pairs and offer a more efficient
200 * way of emptying the buffer than the normal 'dbuf_get' would allow--less
203 * map returns a pointer to a largest contiguous section
204 * of bytes in front of the buffer, the length of the
205 * section is placed into the indicated "long int"
206 * variable. Returns NULL *and* zero length, if the
209 * delete removes the specified number of bytes from the
210 * front of the buffer releasing any memory used for them.
212 * Example use (ignoring empty condition here ;)
214 * buf = dbuf_map(&dyn, &count);
215 * <process N bytes (N <= count) of data pointed by 'buf'>
216 * dbuf_delete(&dyn, N);
218 * Note: delete can be used alone, there is no real binding
219 * between map and delete functions...
221 * dyn: Dynamic buffer header
222 * length: Return number of bytes accessible
224 const char *dbuf_map(const struct DBuf* dyn, unsigned int* length)
229 if (0 == dyn->length)
234 assert(0 != dyn->head);
236 *length = dyn->head->end - dyn->head->start;
237 return dyn->head->start;
241 * dbuf_delete - delete length bytes from DBuf
243 * dyn: Dynamic buffer header
244 * length: Number of bytes to delete
246 void dbuf_delete(struct DBuf *dyn, unsigned int length)
248 struct DBufBuffer *db;
251 if (length > dyn->length)
252 length = dyn->length;
256 if (0 == (db = dyn->head))
258 chunk = db->end - db->start;
263 dyn->length -= chunk;
266 if (db->start == db->end)
268 dyn->head = db->next;
282 * Remove number of bytes from the buffer, releasing dynamic memory,
283 * if applicaple. Bytes are copied from internal buffers to users buffer.
285 * Returns the number of bytes actually copied to users buffer,
286 * if >= 0, any value less than the size of the users
287 * buffer indicates the dbuf became empty by this operation.
289 * Return 0 indicates that buffer was already empty.
291 * dyn: Dynamic buffer header
292 * buf: Pointer to buffer to receive the data
293 * length: Max amount of bytes that can be received
295 unsigned int dbuf_get(struct DBuf *dyn, char *buf, unsigned int length)
297 unsigned int moved = 0;
304 while (length > 0 && (b = dbuf_map(dyn, &chunk)) != 0)
309 memcpy(buf, b, chunk);
310 dbuf_delete(dyn, chunk);
319 static unsigned int dbuf_flush(struct DBuf *dyn)
321 struct DBufBuffer *db = dyn->head;
326 assert(db->start < db->end);
328 * flush extra line terms
330 while (IsEol(*db->start))
332 if (++db->start == db->end)
334 dyn->head = db->next;
336 if (0 == (db = dyn->head))
350 * dbuf_getmsg - Check the buffers to see if there is a string which is
351 * terminated with either a \r or \n present. If so, copy as much as
352 * possible (determined by length) into buf and return the amount copied
355 unsigned int dbuf_getmsg(struct DBuf *dyn, char *buf, unsigned int length)
357 struct DBufBuffer *db;
361 unsigned int copied = 0;
366 if (0 == dbuf_flush(dyn))
369 assert(0 != dyn->head);
374 assert(start < db->end);
376 if (length > dyn->length)
377 length = dyn->length;
379 * might as well copy it while we're here
383 end = IRCD_MIN(db->end, (start + length));
384 while (start < end && !IsEol(*start))
387 count = start - db->start;
392 dbuf_delete(dyn, copied);
396 if (0 == (db = db->next))