]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/rawbuf.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / libratbox / src / rawbuf.c
1 /*
2 * ircd-ratbox: A slight useful ircd
3 * rawbuf.c: raw buffer (non-line oriented buffering)
4 *
5 * Copyright (C) 2007 Aaron Sethman <androsyn@ratbox.org>
6 * Copyright (C) 2007 ircd-ratbox development team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 *
23 * $Id$
24 */
25 #include <libratbox_config.h>
26 #include <ratbox_lib.h>
27 #include <commio-int.h>
28 #define RAWBUF_SIZE 1024
29
30 struct _rawbuf
31 {
32 rb_dlink_node node;
33 uint8_t data[RAWBUF_SIZE];
34 int len;
35 uint8_t flushing;
36 };
37
38 struct _rawbuf_head
39 {
40 rb_dlink_list list;
41 int len;
42 int written;
43 };
44
45 static rb_bh *rawbuf_heap;
46
47
48 static rawbuf_t *
49 rb_rawbuf_alloc(void)
50 {
51 rawbuf_t *t;
52 t = rb_bh_alloc(rawbuf_heap);
53 return t;
54 }
55
56 static rawbuf_t *
57 rb_rawbuf_newbuf(rawbuf_head_t * rb)
58 {
59 rawbuf_t *buf;
60 buf = rb_rawbuf_alloc();
61 rb_dlinkAddTail(buf, &buf->node, &rb->list);
62 return buf;
63 }
64
65 static void
66 rb_rawbuf_done(rawbuf_head_t * rb, rawbuf_t * buf)
67 {
68 rawbuf_t *ptr = buf;
69 rb_dlinkDelete(&buf->node, &rb->list);
70 rb_bh_free(rawbuf_heap, ptr);
71 }
72
73 static int
74 rb_rawbuf_flush_writev(rawbuf_head_t * rb, rb_fde_t *F)
75 {
76 rb_dlink_node *ptr, *next;
77 rawbuf_t *buf;
78 int x = 0, y = 0;
79 int xret, retval;
80 struct rb_iovec vec[RB_UIO_MAXIOV];
81 memset(vec, 0, sizeof(vec));
82
83 if(rb->list.head == NULL)
84 {
85 errno = EAGAIN;
86 return -1;
87 }
88
89 RB_DLINK_FOREACH(ptr, rb->list.head)
90 {
91 if(x >= RB_UIO_MAXIOV)
92 break;
93
94 buf = ptr->data;
95 if(buf->flushing)
96 {
97 vec[x].iov_base = buf->data + rb->written;
98 vec[x++].iov_len = buf->len - rb->written;
99 continue;
100 }
101 vec[x].iov_base = buf->data;
102 vec[x++].iov_len = buf->len;
103
104 }
105
106 if(x == 0)
107 {
108 errno = EAGAIN;
109 return -1;
110 }
111 xret = retval = rb_writev(F, vec, x);
112 if(retval <= 0)
113 return retval;
114
115 RB_DLINK_FOREACH_SAFE(ptr, next, rb->list.head)
116 {
117 buf = ptr->data;
118 if(y++ >= x)
119 break;
120 if(buf->flushing)
121 {
122 if(xret >= buf->len - rb->written)
123 {
124 xret -= buf->len - rb->written;
125 rb->len -= buf->len - rb->written;
126 rb_rawbuf_done(rb, buf);
127 continue;
128 }
129 }
130
131 if(xret >= buf->len)
132 {
133 xret -= buf->len;
134 rb->len -= buf->len;
135 rb_rawbuf_done(rb, buf);
136 }
137 else
138 {
139 buf->flushing = 1;
140 rb->written = xret;
141 rb->len -= xret;
142 break;
143 }
144
145 }
146 return retval;
147 }
148
149 int
150 rb_rawbuf_flush(rawbuf_head_t * rb, rb_fde_t *F)
151 {
152 rawbuf_t *buf;
153 int retval;
154 if(rb->list.head == NULL)
155 {
156 errno = EAGAIN;
157 return -1;
158 }
159
160 if(!rb_fd_ssl(F))
161 return rb_rawbuf_flush_writev(rb, F);
162
163 buf = rb->list.head->data;
164 if(!buf->flushing)
165 {
166 buf->flushing = 1;
167 rb->written = 0;
168 }
169
170 retval = rb_write(F, buf->data + rb->written, buf->len - rb->written);
171 if(retval <= 0)
172 return retval;
173
174 rb->written += retval;
175 if(rb->written == buf->len)
176 {
177 rb->written = 0;
178 rb_dlinkDelete(&buf->node, &rb->list);
179 rb_bh_free(rawbuf_heap, buf);
180 }
181 rb->len -= retval;
182 lrb_assert(rb->len >= 0);
183 return retval;
184 }
185
186
187 void
188 rb_rawbuf_append(rawbuf_head_t * rb, void *data, int len)
189 {
190 rawbuf_t *buf = NULL;
191 int clen;
192 void *ptr;
193 if(rb->list.tail != NULL)
194 buf = rb->list.tail->data;
195
196 if(buf != NULL && buf->len < RAWBUF_SIZE && !buf->flushing)
197 {
198 buf = (rawbuf_t *) rb->list.tail->data;
199 clen = RAWBUF_SIZE - buf->len;
200 ptr = (void *)(buf->data + buf->len);
201 if(len < clen)
202 clen = len;
203
204 memcpy(ptr, data, clen);
205 buf->len += clen;
206 rb->len += clen;
207 len -= clen;
208 if(len == 0)
209 return;
210 data = (char *)data + clen;
211
212 }
213
214 while(len > 0)
215 {
216 buf = rb_rawbuf_newbuf(rb);
217
218 if(len >= RAWBUF_SIZE)
219 clen = RAWBUF_SIZE;
220 else
221 clen = len;
222
223 memcpy(buf->data, data, clen);
224 buf->len += clen;
225 len -= clen;
226 data = (char *)data + clen;
227 rb->len += clen;
228 }
229 }
230
231
232 int
233 rb_rawbuf_get(rawbuf_head_t * rb, void *data, int len)
234 {
235 rawbuf_t *buf;
236 int cpylen;
237 void *ptr;
238 if(rb->list.head == NULL)
239 return 0;
240
241 buf = rb->list.head->data;
242
243 if(buf->flushing)
244 ptr = (void *)(buf->data + rb->written);
245 else
246 ptr = buf->data;
247
248 if(len > buf->len)
249 cpylen = buf->len;
250 else
251 cpylen = len;
252
253 memcpy(data, ptr, cpylen);
254
255 if(cpylen == buf->len)
256 {
257 rb->written = 0;
258 rb_rawbuf_done(rb, buf);
259 rb->len -= len;
260 return cpylen;
261 }
262
263 buf->flushing = 1;
264 buf->len -= cpylen;
265 rb->len -= cpylen;
266 rb->written += cpylen;
267 return cpylen;
268 }
269
270 int
271 rb_rawbuf_length(rawbuf_head_t * rb)
272 {
273 if(rb_dlink_list_length(&rb->list) == 0 && rb->len != 0)
274 lrb_assert(1 == 0);
275 return rb->len;
276 }
277
278 rawbuf_head_t *
279 rb_new_rawbuffer(void)
280 {
281 return rb_malloc(sizeof(rawbuf_head_t));
282
283 }
284
285 void
286 rb_free_rawbuffer(rawbuf_head_t * rb)
287 {
288 rb_dlink_node *ptr, *next;
289 RB_DLINK_FOREACH_SAFE(ptr, next, rb->list.head)
290 {
291 rb_rawbuf_done(rb, ptr->data);
292 }
293 rb_free(rb);
294 }
295
296
297 void
298 rb_init_rawbuffers(int heap_size)
299 {
300 if(rawbuf_heap == NULL)
301 rawbuf_heap = rb_bh_create(sizeof(rawbuf_t), heap_size, "librb_rawbuf_heap");
302 }