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