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