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