chiark / gitweb /
*.[ch]: Remove unnecessary header files.
[mLib] / buf / pkbuf.c
1 /* -*-c-*-
2  *
3  * Simple packet buffering
4  *
5  * (c) 2000 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <string.h>
31
32 #include "alloc.h"
33 #include "arena.h"
34 #include "pkbuf.h"
35
36 /*----- Main code ---------------------------------------------------------*/
37
38 /* --- @pkbuf_flush@ --- *
39  *
40  * Arguments:   @pkbuf *pk@ = pointer to buffer block
41  *              @octet *p@ = pointer to where to start searching
42  *              @size_t len@ = length of new material added
43  *
44  * Returns:     ---
45  *
46  * Use:         Flushes any complete packets in a packet buffer.  New
47  *              material is assumed to have been added starting at @p@.  If
48  *              @p@ is null, then the scan starts at the beginning of the
49  *              buffer, and the size of data already in the buffer is used in
50  *              place of @len@.
51  *
52  *              It is assumed that the buffer is initially enabled.  You
53  *              shouldn't be contributing data to a disabled buffer anyway.
54  *              However, the buffer handler may at some point disable itself,
55  *              and @pkbuf_flush@ can cope with this eventuality.  Any
56  *              pending data is left at the start of the buffer and can be
57  *              flushed out by calling @pkbuf_flush(b, 0, 0)@ if the buffer
58  *              is ever re-enabled.
59  */
60
61 void pkbuf_flush(pkbuf *pk, octet *p, size_t len)
62 {
63   size_t l;
64   size_t o, keep;
65
66   if (pk->f & PKBUF_CLOSE) {
67     pk->func(0, 0, pk, 0, pk->p);
68     return;
69   }
70
71   /* --- Initialize variables as necessary --- */
72
73   if (!p) {
74     p = pk->buf;
75     len = pk->len;
76   }
77   l = p + len - pk->buf;
78   o = 0;
79
80   /* --- Now grind through any packets which have accumulated --- */
81
82   pk->len = l;
83   while (l >= pk->want) {
84     size_t sz = pk->want;
85
86     /* --- Pass a packet to the user handler --- */
87
88     keep = 0;
89     pk->func(pk->buf + o, sz, pk, &keep, pk->p);
90
91     /* --- Adjust all the pointers for the next packet --- */
92
93     sz -= keep;
94     o += sz;
95     l -= sz;
96
97     /* --- Abort here if disabled --- */
98
99     if (!(pk->f & PKBUF_ENABLE))
100       break;
101   }
102
103   /* --- Shunt data around in the buffer --- */
104
105   if (o > 0 && l != 0)
106     memmove(pk->buf, pk->buf + o, l);
107   pk->len = l;
108 }
109
110 /* --- @pkbuf_close@ --- *
111  *
112  * Arguments:   @pkbuf *pk@ = pointer to buffer block
113  *
114  * Returns:     ---
115  *
116  * Use:         Informs the client that no more data is likely to arrive.  If
117  *              there is a partial packet in the buffer, it is discarded.
118  */
119
120 void pkbuf_close(pkbuf *pk)
121 {
122   if (pk->buf) {
123     x_free(pk->a, pk->buf);
124     pk->buf = 0;
125   }
126   pk->f |= PKBUF_CLOSE;
127   if (pk->f & PKBUF_ENABLE)
128     pk->func(0, 0, pk, 0, pk->p);
129 }
130
131 /* --- @pkbuf_free@ --- *
132  *
133  * Arguments:   @pkbuf *pk@ = pointer to buffer block
134  *              @octet **p@ = output pointer to free space
135  *
136  * Returns:     Free buffer size.
137  *
138  * Use:         Returns the free portion of a packet buffer.  Data can then
139  *              be written to this portion, and split out into packets by
140  *              calling @pkbuf_flush@.  A buffer is allocated if none
141  *              currently exists.
142  */
143
144 size_t pkbuf_free(pkbuf *pk, octet **p)
145 {
146   if (!pk->buf)
147     pk->buf = x_alloc(pk->a, pk->sz);
148   *p = pk->buf + pk->len;
149   return (pk->sz - pk->len);
150 }
151
152 /* --- @pkbuf_snarf@ --- *
153  *
154  * Arguments:   @pkbuf *pk@ = pointer to buffer block
155  *              @const void *p@ = pointer to input data buffer
156  *              @size_t sz@ = size of data in input buffer
157  *
158  * Returns:     ---
159  *
160  * Use:         Snarfs the data from the input buffer and spits it out as
161  *              packets.  This interface ignores the complexities of dealing
162  *              with disablement: you should be using @pkbuf_free@ to
163  *              contribute data if you want to cope with that.
164  */
165
166 void pkbuf_snarf(pkbuf *pk, const void *p, size_t sz)
167 {
168   const octet *pp = p;
169   while (sz && (pk->f & PKBUF_ENABLE)) {
170     size_t bsz;
171     octet *bp;
172
173     bsz = pkbuf_free(pk, &bp);
174     if (bsz > sz)
175       bsz = sz;
176     memcpy(bp, pp, bsz);
177     pkbuf_flush(pk, bp, bsz);
178     pp += bsz;
179     sz -= bsz;
180   }
181 }
182
183 /* --- @pkbuf_want@ --- *
184  *
185  * Arguments:   @pkbuf *pk@ = pointer to buffer block
186  *              @size_t want@ = how many octets wanted for next packet
187  *
188  * Returns:     ---
189  *
190  * Use:         Sets the desired size for the next packet to be read.  If
191  *              it's larger than the current buffer, the buffer is extended.
192  */
193
194 void pkbuf_want(pkbuf *pk, size_t want)
195 {
196   pk->want = want;
197   if (want > pk->sz) {
198     do pk->sz <<= 1; while (want > pk->sz);
199     if (pk->buf) {
200       if (pk->len)
201         pk->buf = x_realloc(pk->a, pk->buf, pk->sz, pk->len);
202       else {
203         x_free(pk->a, pk->buf);
204         pk->buf = 0;
205       }
206     }
207   }
208 }
209
210 /* --- @pkbuf_init@ --- *
211  *
212  * Arguments:   @pkbuf *pk@ = pointer to buffer block
213  *              @pkbuf *func@ = handler function
214  *              @void *p@ = argument pointer for @func@
215  *
216  * Returns:     ---
217  *
218  * Use:         Initializes a packet buffer block.  Any packets are passed to
219  *              the provided function for handling.
220  */
221
222 void pkbuf_init(pkbuf *pk, pkbuf_func *func, void *p)
223 {
224   pk->func = func;
225   pk->p = p;
226   pk->len = 0;
227   pk->f = PKBUF_ENABLE;
228   pk->buf = 0;
229   pk->sz = 256;
230   pk->want = 1;
231   pk->a = arena_global;
232 }
233
234 /* --- @pkbuf_destroy@ --- *
235  *
236  * Arguments:   @pkbuf *pk@ = pointer to buffer block
237  *
238  * Returns:     ---
239  *
240  * Use:         Deallocates a line buffer and frees any resources it owned.
241  */
242
243 void pkbuf_destroy(pkbuf *pk)
244 {
245   if (pk->buf) {
246     x_free(pk->a, pk->buf);
247     pk->buf = 0;
248   }
249 }
250
251 /*----- That's all, folks -------------------------------------------------*/