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.
24 #include "ircd_alloc.h"
25 #include "ircd_chattr.h"
26 #include "ircd_features.h"
28 #include "sys.h" /* MIN */
34 * dbuf is a collection of functions which can be used to
35 * maintain a dynamic buffering of a byte stream.
36 * Functions allocate and release memory dynamically as
37 * required [Actually, there is nothing that prevents
38 * this package maintaining the buffer on disk, either]
41 int DBufAllocCount = 0;
42 int DBufUsedCount = 0;
44 static struct DBufBuffer *dbufFreeList = 0;
46 #define DBUF_SIZE 2048
49 struct DBufBuffer *next; /* Next data buffer, NULL if last */
50 char *start; /* data starts here */
51 char *end; /* data ends here */
52 char data[DBUF_SIZE]; /* Actual data stored here */
55 void dbuf_count_memory(size_t *allocated, size_t *used)
57 assert(0 != allocated);
59 *allocated = DBufAllocCount * sizeof(struct DBufBuffer);
60 *used = DBufUsedCount * sizeof(struct DBufBuffer);
64 * dbuf_alloc - allocates a DBufBuffer structure from the free list or
67 static struct DBufBuffer *dbuf_alloc(void)
69 struct DBufBuffer* db = dbufFreeList;
72 dbufFreeList = db->next;
75 else if (DBufAllocCount * DBUF_SIZE < feature_int(FEAT_BUFFERPOOL)) {
76 db = (struct DBufBuffer*) MyMalloc(sizeof(struct DBufBuffer));
85 * dbuf_free - return a struct DBufBuffer structure to the freelist
87 static void dbuf_free(struct DBufBuffer *db)
91 db->next = dbufFreeList;
96 * This is called when malloc fails. Scrap the whole content
97 * of dynamic buffer. (malloc errors are FATAL, there is no
98 * reason to continue this buffer...).
99 * After this the "dbuf" has consistent EMPTY status.
101 static int dbuf_malloc_error(struct DBuf *dyn)
103 struct DBufBuffer *db;
104 struct DBufBuffer *next;
106 for (db = dyn->head; db; db = next)
111 dyn->tail = dyn->head = 0;
117 * dbuf_put - Append the number of bytes to the buffer, allocating memory
118 * as needed. Bytes are copied into internal buffers from users buffer.
120 * Returns > 0, if operation successful
121 * < 0, if failed (due memory allocation problem)
123 * dyn: Dynamic buffer header
124 * buf: Pointer to data to be stored
125 * length: Number of bytes to store
127 int dbuf_put(struct DBuf *dyn, const char *buf, unsigned int length)
129 struct DBufBuffer** h;
130 struct DBufBuffer* db;
136 * Locate the last non-empty buffer. If the last buffer is full,
137 * the loop will terminate with 'db==NULL'.
138 * This loop assumes that the 'dyn->length' field is correctly
139 * maintained, as it should--no other check really needed.
146 * Append users data to buffer, allocating buffers as needed
148 dyn->length += length;
150 for (; length > 0; h = &(db->next)) {
151 if (0 == (db = *h)) {
152 if (0 == (db = dbuf_alloc())) {
153 if (feature_bool(FEAT_HAS_FERGUSON_FLUSHER)) {
155 * from "Married With Children" episode were Al bought a REAL toilet
156 * on the black market because he was tired of the wimpy water
157 * conserving toilets they make these days --Bleep
160 * Apparently this doesn't work, the server _has_ to
161 * dump a few clients to handle the load. A fully loaded
162 * server cannot handle a net break without dumping some
163 * clients. If we flush the connections here under a full
164 * load we may end up starving the kernel for mbufs and
168 * attempt to recover from buffer starvation before
169 * bailing this may help servers running out of memory
171 flush_connections(0);
176 return dbuf_malloc_error(dyn);
181 db->start = db->end = db->data;
183 chunk = (db->data + DBUF_SIZE) - db->end;
188 memcpy(db->end, buf, chunk);
199 * dbuf_map, dbuf_delete
201 * These functions are meant to be used in pairs and offer a more efficient
202 * way of emptying the buffer than the normal 'dbuf_get' would allow--less
205 * map returns a pointer to a largest contiguous section
206 * of bytes in front of the buffer, the length of the
207 * section is placed into the indicated "long int"
208 * variable. Returns NULL *and* zero length, if the
211 * delete removes the specified number of bytes from the
212 * front of the buffer releasing any memory used for them.
214 * Example use (ignoring empty condition here ;)
216 * buf = dbuf_map(&dyn, &count);
217 * <process N bytes (N <= count) of data pointed by 'buf'>
218 * dbuf_delete(&dyn, N);
220 * Note: delete can be used alone, there is no real binding
221 * between map and delete functions...
223 * dyn: Dynamic buffer header
224 * length: Return number of bytes accessible
226 const char *dbuf_map(const struct DBuf* dyn, unsigned int* length)
231 if (0 == dyn->length)
236 assert(0 != dyn->head);
238 *length = dyn->head->end - dyn->head->start;
239 return dyn->head->start;
243 * dbuf_delete - delete length bytes from DBuf
245 * dyn: Dynamic buffer header
246 * length: Number of bytes to delete
248 void dbuf_delete(struct DBuf *dyn, unsigned int length)
250 struct DBufBuffer *db;
253 if (length > dyn->length)
254 length = dyn->length;
258 if (0 == (db = dyn->head))
260 chunk = db->end - db->start;
265 dyn->length -= chunk;
268 if (db->start == db->end)
270 dyn->head = db->next;
284 * Remove number of bytes from the buffer, releasing dynamic memory,
285 * if applicaple. Bytes are copied from internal buffers to users buffer.
287 * Returns the number of bytes actually copied to users buffer,
288 * if >= 0, any value less than the size of the users
289 * buffer indicates the dbuf became empty by this operation.
291 * Return 0 indicates that buffer was already empty.
293 * dyn: Dynamic buffer header
294 * buf: Pointer to buffer to receive the data
295 * length: Max amount of bytes that can be received
297 unsigned int dbuf_get(struct DBuf *dyn, char *buf, unsigned int length)
299 unsigned int moved = 0;
306 while (length > 0 && (b = dbuf_map(dyn, &chunk)) != 0)
311 memcpy(buf, b, chunk);
312 dbuf_delete(dyn, chunk);
321 static unsigned int dbuf_flush(struct DBuf *dyn)
323 struct DBufBuffer *db = dyn->head;
328 assert(db->start < db->end);
330 * flush extra line terms
332 while (IsEol(*db->start))
334 if (++db->start == db->end)
336 dyn->head = db->next;
338 if (0 == (db = dyn->head))
352 * dbuf_getmsg - Check the buffers to see if there is a string which is
353 * terminated with either a \r or \n present. If so, copy as much as
354 * possible (determined by length) into buf and return the amount copied
357 unsigned int dbuf_getmsg(struct DBuf *dyn, char *buf, unsigned int length)
359 struct DBufBuffer *db;
363 unsigned int copied = 0;
368 if (0 == dbuf_flush(dyn))
371 assert(0 != dyn->head);
376 assert(start < db->end);
378 if (length > dyn->length)
379 length = dyn->length;
381 * might as well copy it while we're here
385 end = IRCD_MIN(db->end, (start + length));
386 while (start < end && !IsEol(*start))
389 count = start - db->start;
394 dbuf_delete(dyn, copied);
398 if (0 == (db = db->next))