]> jfr.im git - solanum.git/blob - librb/src/rawbuf.c
librb/helper: call rb_clear_cloexec on child fds
[solanum.git] / librb / 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 */
24 #include <librb_config.h>
25 #include <rb_lib.h>
26 #include <commio-int.h>
27 #define RAWBUF_SIZE 1024
28
29 struct _rawbuf
30 {
31 rb_dlink_node node;
32 uint8_t data[RAWBUF_SIZE];
33 int len;
34 uint8_t flushing;
35 };
36
37 struct _rawbuf_head
38 {
39 rb_dlink_list list;
40 int len;
41 int written;
42 };
43
44 static rb_bh *rawbuf_heap;
45
46
47 static rawbuf_t *
48 rb_rawbuf_alloc(void)
49 {
50 rawbuf_t *t;
51 t = rb_bh_alloc(rawbuf_heap);
52 return t;
53 }
54
55 static rawbuf_t *
56 rb_rawbuf_newbuf(rawbuf_head_t * rb)
57 {
58 rawbuf_t *buf;
59 buf = rb_rawbuf_alloc();
60 rb_dlinkAddTail(buf, &buf->node, &rb->list);
61 return buf;
62 }
63
64 static void
65 rb_rawbuf_done(rawbuf_head_t * rb, rawbuf_t * buf)
66 {
67 rawbuf_t *ptr = buf;
68 rb_dlinkDelete(&buf->node, &rb->list);
69 rb_bh_free(rawbuf_heap, ptr);
70 }
71
72 static int
73 rb_rawbuf_flush_writev(rawbuf_head_t * rb, rb_fde_t *F)
74 {
75 rb_dlink_node *ptr, *next;
76 rawbuf_t *buf;
77 int x = 0, y = 0;
78 int xret, retval;
79 struct rb_iovec vec[RB_UIO_MAXIOV];
80 memset(vec, 0, sizeof(vec));
81
82 if(rb->list.head == NULL)
83 {
84 errno = EAGAIN;
85 return -1;
86 }
87
88 RB_DLINK_FOREACH(ptr, rb->list.head)
89 {
90 if(x >= RB_UIO_MAXIOV)
91 break;
92
93 buf = ptr->data;
94 if(buf->flushing)
95 {
96 vec[x].iov_base = buf->data + rb->written;
97 vec[x++].iov_len = buf->len - rb->written;
98 continue;
99 }
100 vec[x].iov_base = buf->data;
101 vec[x++].iov_len = buf->len;
102
103 }
104
105 if(x == 0)
106 {
107 errno = EAGAIN;
108 return -1;
109 }
110 xret = retval = rb_writev(F, vec, x);
111 if(retval <= 0)
112 return retval;
113
114 RB_DLINK_FOREACH_SAFE(ptr, next, rb->list.head)
115 {
116 buf = ptr->data;
117 if(y++ >= x)
118 break;
119 if(buf->flushing)
120 {
121 if(xret >= buf->len - rb->written)
122 {
123 xret -= buf->len - rb->written;
124 rb->len -= buf->len - rb->written;
125 rb_rawbuf_done(rb, buf);
126 continue;
127 }
128 }
129
130 if(xret >= buf->len)
131 {
132 xret -= buf->len;
133 rb->len -= buf->len;
134 rb_rawbuf_done(rb, buf);
135 }
136 else
137 {
138 buf->flushing = 1;
139 rb->written = xret;
140 rb->len -= xret;
141 break;
142 }
143
144 }
145 return retval;
146 }
147
148 int
149 rb_rawbuf_flush(rawbuf_head_t * rb, rb_fde_t *F)
150 {
151 rawbuf_t *buf;
152 int retval;
153 if(rb->list.head == NULL)
154 {
155 errno = EAGAIN;
156 return -1;
157 }
158
159 if(!rb_fd_ssl(F))
160 return rb_rawbuf_flush_writev(rb, F);
161
162 buf = rb->list.head->data;
163 if(!buf->flushing)
164 {
165 buf->flushing = 1;
166 rb->written = 0;
167 }
168
169 retval = rb_write(F, buf->data + rb->written, buf->len - rb->written);
170 if(retval <= 0)
171 return retval;
172
173 rb->written += retval;
174 if(rb->written == buf->len)
175 {
176 rb->written = 0;
177 rb_dlinkDelete(&buf->node, &rb->list);
178 rb_bh_free(rawbuf_heap, buf);
179 }
180 rb->len -= retval;
181 lrb_assert(rb->len >= 0);
182 return retval;
183 }
184
185
186 void
187 rb_rawbuf_append(rawbuf_head_t * rb, void *data, int len)
188 {
189 rawbuf_t *buf = NULL;
190 int clen;
191 void *ptr;
192 if(rb->list.tail != NULL)
193 buf = rb->list.tail->data;
194
195 if(buf != NULL && buf->len < RAWBUF_SIZE && !buf->flushing)
196 {
197 buf = (rawbuf_t *) rb->list.tail->data;
198 clen = RAWBUF_SIZE - buf->len;
199 ptr = (void *)(buf->data + buf->len);
200 if(len < clen)
201 clen = len;
202
203 memcpy(ptr, data, clen);
204 buf->len += clen;
205 rb->len += clen;
206 len -= clen;
207 if(len == 0)
208 return;
209 data = (char *)data + clen;
210
211 }
212
213 while(len > 0)
214 {
215 buf = rb_rawbuf_newbuf(rb);
216
217 if(len >= RAWBUF_SIZE)
218 clen = RAWBUF_SIZE;
219 else
220 clen = len;
221
222 memcpy(buf->data, data, clen);
223 buf->len += clen;
224 len -= clen;
225 data = (char *)data + clen;
226 rb->len += clen;
227 }
228 }
229
230
231 int
232 rb_rawbuf_get(rawbuf_head_t * rb, void *data, int len)
233 {
234 rawbuf_t *buf;
235 int cpylen;
236 void *ptr;
237 if(rb->list.head == NULL)
238 return 0;
239
240 buf = rb->list.head->data;
241
242 if(buf->flushing)
243 ptr = (void *)(buf->data + rb->written);
244 else
245 ptr = buf->data;
246
247 if(len > buf->len)
248 cpylen = buf->len;
249 else
250 cpylen = len;
251
252 memcpy(data, ptr, cpylen);
253
254 if(cpylen == buf->len)
255 {
256 rb->written = 0;
257 rb_rawbuf_done(rb, buf);
258 rb->len -= len;
259 return cpylen;
260 }
261
262 buf->flushing = 1;
263 buf->len -= cpylen;
264 rb->len -= cpylen;
265 rb->written += cpylen;
266 return cpylen;
267 }
268
269 int
270 rb_rawbuf_length(rawbuf_head_t * rb)
271 {
272 if (rb_dlink_list_length(&rb->list) == 0 && lrb_assert(rb->len == 0))
273 rb->len = 0;
274 return rb->len;
275 }
276
277 rawbuf_head_t *
278 rb_new_rawbuffer(void)
279 {
280 return rb_malloc(sizeof(rawbuf_head_t));
281
282 }
283
284 void
285 rb_free_rawbuffer(rawbuf_head_t * rb)
286 {
287 rb_dlink_node *ptr, *next;
288 RB_DLINK_FOREACH_SAFE(ptr, next, rb->list.head)
289 {
290 rb_rawbuf_done(rb, ptr->data);
291 }
292 rb_free(rb);
293 }
294
295
296 void
297 rb_init_rawbuffers(int heap_size)
298 {
299 if(rawbuf_heap == NULL)
300 rawbuf_heap = rb_bh_create(sizeof(rawbuf_t), heap_size, "librb_rawbuf_heap");
301 }