unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
dbuf.c (5018B)
1 /* 2 * UnrealIRCd, src/dbuf.c 3 * Copyright (c) 2013 William Pitcock <nenolod@dereferenced.org> 4 * 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) 8 * any later version. 9 * 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. 14 * 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. 18 */ 19 20 #include "unrealircd.h" 21 22 static mp_pool_t *dbuf_bufpool = NULL; 23 24 void dbuf_init(void) 25 { 26 dbuf_bufpool = mp_pool_new(sizeof(struct dbufbuf), 512 * 1024); 27 } 28 29 /* 30 ** dbuf_alloc - allocates a dbufbuf structure either from freelist or 31 ** creates a new one. 32 */ 33 static dbufbuf *dbuf_alloc(dbuf *dbuf_p) 34 { 35 dbufbuf *ptr; 36 37 assert(dbuf_p != NULL); 38 39 ptr = mp_pool_get(dbuf_bufpool); 40 memset(ptr, 0, sizeof(dbufbuf)); 41 42 INIT_LIST_HEAD(&ptr->dbuf_node); 43 list_add_tail(&ptr->dbuf_node, &dbuf_p->dbuf_list); 44 45 return ptr; 46 } 47 48 /* 49 ** dbuf_free - return a dbufbuf structure to the freelist 50 */ 51 static void dbuf_free(dbufbuf *ptr) 52 { 53 assert(ptr != NULL); 54 55 list_del(&ptr->dbuf_node); 56 mp_pool_release(ptr); 57 } 58 59 void dbuf_queue_init(dbuf *dyn) 60 { 61 memset(dyn, 0, sizeof(dbuf)); 62 INIT_LIST_HEAD(&dyn->dbuf_list); 63 } 64 65 void dbuf_put(dbuf *dyn, const char *buf, size_t length) 66 { 67 struct dbufbuf *block; 68 size_t amount; 69 70 assert(length > 0); 71 if (list_empty(&dyn->dbuf_list)) 72 dbuf_alloc(dyn); 73 74 while (length > 0) 75 { 76 block = container_of(dyn->dbuf_list.prev, struct dbufbuf, dbuf_node); 77 78 amount = DBUF_BLOCK_SIZE - block->size; 79 if (!amount) 80 { 81 block = dbuf_alloc(dyn); 82 amount = DBUF_BLOCK_SIZE; 83 } 84 if (amount > length) 85 amount = length; 86 87 memcpy(&block->data[block->size], buf, amount); 88 89 length -= amount; 90 block->size += amount; 91 dyn->length += amount; 92 buf += amount; 93 } 94 } 95 96 void dbuf_delete(dbuf *dyn, size_t length) 97 { 98 struct dbufbuf *block; 99 100 assert(dyn->length >= length); 101 if (length == 0) 102 return; 103 104 for (;;) 105 { 106 if (length == 0) 107 return; 108 109 block = container_of(dyn->dbuf_list.next, struct dbufbuf, dbuf_node); 110 if (length < block->size) 111 break; 112 113 dyn->length -= block->size; 114 length -= block->size; 115 dbuf_free(block); 116 } 117 118 block->size -= length; 119 dyn->length -= length; 120 memmove(block->data, &block->data[length], block->size); 121 } 122 123 /* 124 ** dbuf_getmsg 125 ** 126 ** Check the buffers to see if there is a string which is terminted with 127 ** either a \r or \n prsent. If so, copy as much as possible (determined by 128 ** length) into buf and return the amount copied - else return 0. 129 ** 130 ** Partially based on extract_one_line() from ircd-hybrid. --kaniini 131 */ 132 int dbuf_getmsg(dbuf *dyn, char *buf) 133 { 134 dbufbuf *block; 135 int line_bytes = 0, empty_bytes = 0, phase = 0; 136 unsigned int idx; 137 char c; 138 char *p = buf; 139 140 /* 141 * Phase 0: "empty" characters before the line 142 * Phase 1: copying the line 143 * Phase 2: "empty" characters after the line 144 * (delete them as well and free some space in the dbuf) 145 * 146 * Empty characters are CR, LF and space (but, of course, not 147 * in the middle of a line). We try to remove as much of them as we can, 148 * since they simply eat server memory. 149 * 150 * --adx 151 */ 152 list_for_each_entry2(block, dbufbuf, &dyn->dbuf_list, dbuf_node) 153 { 154 for (idx = 0; idx < block->size; idx++) 155 { 156 c = block->data[idx]; 157 if (c == '\r' || c == '\n' || (c == ' ' && phase != 1)) 158 { 159 empty_bytes++; 160 if (phase == 1) 161 phase = 2; 162 } 163 else switch (phase) 164 { 165 case 0: phase = 1; /* FALLTHROUGH */ 166 case 1: if (line_bytes++ < READBUFSIZE - 2) 167 *p++ = c; 168 break; 169 case 2: *p = '\0'; 170 dbuf_delete(dyn, line_bytes + empty_bytes); 171 return MIN(line_bytes, READBUFSIZE - 2); 172 } 173 } 174 } 175 176 if (phase != 2) 177 { 178 /* If we have not reached phase 2 then this is not 179 * not a complete line and it is invalid (return 0). 180 */ 181 line_bytes = 0; 182 *buf = '\0'; 183 } else { 184 /* Zero terminate the string */ 185 *p = '\0'; 186 } 187 188 /* Remove what is now unnecessary */ 189 dbuf_delete(dyn, line_bytes + empty_bytes); 190 return MIN(line_bytes, READBUFSIZE - 2); 191 } 192 193 /* 194 ** dbuf_get 195 ** 196 ** Get the entire dbuf buffer as a newly allocated string. There is NO CR/LF processing. 197 */ 198 int dbuf_get(dbuf *dyn, char **buf) 199 { 200 dbufbuf *block; 201 char *d; 202 int bytes = 0; 203 204 /* First calculate the room needed... */ 205 list_for_each_entry2(block, dbufbuf, &dyn->dbuf_list, dbuf_node) 206 bytes += block->size; 207 208 d = *buf = safe_alloc(bytes + 1); 209 210 list_for_each_entry2(block, dbufbuf, &dyn->dbuf_list, dbuf_node) 211 { 212 memcpy(d, block->data, block->size); 213 d += block->size; 214 } 215 *d = '\0'; /* zero terminate */ 216 217 /* Remove what is now unnecessary */ 218 dbuf_delete(dyn, bytes); 219 return bytes; 220 }