1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * queue.c - simple in-process message queuing
5  *
6  * Written by Steve Underwood <steveu@coppice.org>
7  *
8  * Copyright (C) 2004 Steve Underwood
9  *
10  * All rights reserved.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 2.1,
14  * as published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  * $Id: queue.c,v 1.22 2008/05/15 14:26:30 steveu Exp $
26  */
27 
28 /*! \file */
29 
30 #if defined(HAVE_CONFIG_H)
31 #include <config.h>
32 #endif
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <time.h>
37 #include <ctype.h>
38 #include <stdlib.h>
39 #include <inttypes.h>
40 #include <sys/types.h>
41 
42 #include "spandsp/queue.h"
43 
queue_empty(queue_state_t * s)44 int queue_empty(queue_state_t *s)
45 {
46     return (s->iptr == s->optr);
47 }
48 /*- End of function --------------------------------------------------------*/
49 
queue_free_space(queue_state_t * s)50 int queue_free_space(queue_state_t *s)
51 {
52     int len;
53 
54     if ((len = s->optr - s->iptr - 1) < 0)
55         len += s->len;
56     /*endif*/
57     return len;
58 }
59 /*- End of function --------------------------------------------------------*/
60 
queue_contents(queue_state_t * s)61 int queue_contents(queue_state_t *s)
62 {
63     int len;
64 
65     if ((len = s->iptr - s->optr) < 0)
66         len += s->len;
67     /*endif*/
68     return len;
69 }
70 /*- End of function --------------------------------------------------------*/
71 
queue_flush(queue_state_t * s)72 void queue_flush(queue_state_t *s)
73 {
74     s->optr = s->iptr;
75 }
76 /*- End of function --------------------------------------------------------*/
77 
queue_view(queue_state_t * s,uint8_t * buf,int len)78 int queue_view(queue_state_t *s, uint8_t *buf, int len)
79 {
80     int real_len;
81     int to_end;
82     int iptr;
83     int optr;
84 
85     /* Snapshot the values (although only iptr should be changeable during this processing) */
86     iptr = s->iptr;
87     optr = s->optr;
88     if ((real_len = iptr - optr) < 0)
89         real_len += s->len;
90     /*endif*/
91     if (real_len < len)
92     {
93         if (s->flags & QUEUE_READ_ATOMIC)
94             return -1;
95         /*endif*/
96     }
97     else
98     {
99         real_len = len;
100     }
101     /*endif*/
102     if (real_len == 0)
103         return 0;
104     /*endif*/
105     to_end = s->len - optr;
106     if (iptr < optr  &&  to_end < real_len)
107     {
108         /* A two step process */
109         if (buf)
110         {
111             memcpy(buf, s->data + optr, to_end);
112             memcpy(buf + to_end, s->data, real_len - to_end);
113         }
114         /*endif*/
115     }
116     else
117     {
118         /* A one step process */
119         if (buf)
120             memcpy(buf, s->data + optr, real_len);
121         /*endif*/
122     }
123     /*endif*/
124     return real_len;
125 }
126 /*- End of function --------------------------------------------------------*/
127 
queue_read(queue_state_t * s,uint8_t * buf,int len)128 int queue_read(queue_state_t *s, uint8_t *buf, int len)
129 {
130     int real_len;
131     int to_end;
132     int new_optr;
133     int iptr;
134     int optr;
135 
136     /* Snapshot the values (although only iptr should be changeable during this processing) */
137     iptr = s->iptr;
138     optr = s->optr;
139     if ((real_len = iptr - optr) < 0)
140         real_len += s->len;
141     /*endif*/
142     if (real_len < len)
143     {
144         if (s->flags & QUEUE_READ_ATOMIC)
145             return -1;
146         /*endif*/
147     }
148     else
149     {
150         real_len = len;
151     }
152     /*endif*/
153     if (real_len == 0)
154         return 0;
155     /*endif*/
156     to_end = s->len - optr;
157     if (iptr < optr  &&  to_end < real_len)
158     {
159         /* A two step process */
160         if (buf)
161         {
162             memcpy(buf, s->data + optr, to_end);
163             memcpy(buf + to_end, s->data, real_len - to_end);
164         }
165         /*endif*/
166         new_optr = real_len - to_end;
167     }
168     else
169     {
170         /* A one step process */
171         if (buf)
172             memcpy(buf, s->data + optr, real_len);
173         /*endif*/
174         new_optr = optr + real_len;
175         if (new_optr > s->len)
176             new_optr = 0;
177         /*endif*/
178     }
179     /*endif*/
180     /* Only change the pointer now we have really finished */
181     s->optr = new_optr;
182     return real_len;
183 }
184 /*- End of function --------------------------------------------------------*/
185 
queue_read_byte(queue_state_t * s)186 int queue_read_byte(queue_state_t *s)
187 {
188     int real_len;
189     int to_end;
190     int iptr;
191     int optr;
192     int byte;
193 
194     /* Snapshot the values (although only iptr should be changeable during this processing) */
195     iptr = s->iptr;
196     optr = s->optr;
197     if ((real_len = iptr - optr) < 0)
198         real_len += s->len;
199     /*endif*/
200     if (real_len < 1)
201         return -1;
202     /*endif*/
203     to_end = s->len - optr;
204     byte = s->data[optr];
205     if (++optr >= s->len)
206         optr = 0;
207     /*endif*/
208     /* Only change the pointer now we have really finished */
209     s->optr = optr;
210     return byte;
211 }
212 /*- End of function --------------------------------------------------------*/
213 
queue_write(queue_state_t * s,const uint8_t * buf,int len)214 int queue_write(queue_state_t *s, const uint8_t *buf, int len)
215 {
216     int real_len;
217     int to_end;
218     int new_iptr;
219     int iptr;
220     int optr;
221 
222     /* Snapshot the values (although only optr should be changeable during this processing) */
223     iptr = s->iptr;
224     optr = s->optr;
225 
226     if ((real_len = optr - iptr - 1) < 0)
227         real_len += s->len;
228     /*endif*/
229     if (real_len < len)
230     {
231         if (s->flags & QUEUE_WRITE_ATOMIC)
232             return -1;
233         /*endif*/
234     }
235     else
236     {
237         real_len = len;
238     }
239     /*endif*/
240     if (real_len == 0)
241         return 0;
242     /*endif*/
243     to_end = s->len - iptr;
244     if (iptr < optr  ||  to_end >= real_len)
245     {
246         /* A one step process */
247         memcpy(s->data + iptr, buf, real_len);
248         new_iptr = iptr + real_len;
249         if (new_iptr > s->len)
250             new_iptr = 0;
251         /*endif*/
252     }
253     else
254     {
255         /* A two step process */
256         memcpy(s->data + iptr, buf, to_end);
257         memcpy(s->data, buf + to_end, real_len - to_end);
258         new_iptr = real_len - to_end;
259     }
260     /*endif*/
261     /* Only change the pointer now we have really finished */
262     s->iptr = new_iptr;
263     return real_len;
264 }
265 /*- End of function --------------------------------------------------------*/
266 
queue_write_byte(queue_state_t * s,uint8_t byte)267 int queue_write_byte(queue_state_t *s, uint8_t byte)
268 {
269     int real_len;
270     int iptr;
271     int optr;
272 
273     /* Snapshot the values (although only optr should be changeable during this processing) */
274     iptr = s->iptr;
275     optr = s->optr;
276 
277     if ((real_len = optr - iptr - 1) < 0)
278         real_len += s->len;
279     /*endif*/
280     if (real_len < 1)
281     {
282         if (s->flags & QUEUE_WRITE_ATOMIC)
283             return -1;
284         /*endif*/
285         return 0;
286     }
287     /*endif*/
288     s->data[iptr] = byte;
289     if (++iptr >= s->len)
290         iptr = 0;
291     /*endif*/
292     /* Only change the pointer now we have really finished */
293     s->iptr = iptr;
294     return 1;
295 }
296 /*- End of function --------------------------------------------------------*/
297 
queue_state_test_msg(queue_state_t * s)298 int queue_state_test_msg(queue_state_t *s)
299 {
300     uint16_t lenx;
301 
302     if (queue_view(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t))
303         return -1;
304     /*endif*/
305     return lenx;
306 }
307 /*- End of function --------------------------------------------------------*/
308 
queue_read_msg(queue_state_t * s,uint8_t * buf,int len)309 int queue_read_msg(queue_state_t *s, uint8_t *buf, int len)
310 {
311     uint16_t lenx;
312 
313     /* If we assume the write message was atomic, this read message should be
314       safe when conducted in multiple chunks */
315     if (queue_read(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t))
316         return -1;
317     /*endif*/
318     /* If we got this far, the actual message chunk should be guaranteed to be
319        available */
320     if (lenx == 0)
321         return 0;
322     /*endif*/
323     if ((int) lenx > len)
324     {
325         len = queue_read(s, buf, len);
326         /* Discard the rest of the message */
327         queue_read(s, NULL, lenx - len);
328         return len;
329     }
330     /*endif*/
331     return queue_read(s, buf, lenx);
332 }
333 /*- End of function --------------------------------------------------------*/
334 
queue_write_msg(queue_state_t * s,const uint8_t * buf,int len)335 int queue_write_msg(queue_state_t *s, const uint8_t *buf, int len)
336 {
337     int real_len;
338     int to_end;
339     int new_iptr;
340     int iptr;
341     int optr;
342     uint16_t lenx;
343 
344     /* Snapshot the values (although only optr should be changeable during this processing) */
345     iptr = s->iptr;
346     optr = s->optr;
347 
348     if ((real_len = optr - iptr - 1) < 0)
349         real_len += s->len;
350     /*endif*/
351     if (real_len < len + sizeof(uint16_t))
352         return -1;
353     /*endif*/
354     real_len = len + sizeof(uint16_t);
355 
356     to_end = s->len - iptr;
357     lenx = (uint16_t) len;
358     if (iptr < optr  ||  to_end >= real_len)
359     {
360         /* A one step process */
361         memcpy(s->data + iptr, &lenx, sizeof(uint16_t));
362         memcpy(s->data + iptr + sizeof(uint16_t), buf, len);
363         new_iptr = iptr + real_len;
364         if (new_iptr > s->len)
365             new_iptr = 0;
366         /*endif*/
367     }
368     else
369     {
370         /* A two step process */
371         if (to_end >= sizeof(uint16_t))
372         {
373             /* The actual message wraps around the end of the buffer */
374             memcpy(s->data + iptr, &lenx, sizeof(uint16_t));
375             memcpy(s->data + iptr + sizeof(uint16_t), buf, to_end - sizeof(uint16_t));
376             memcpy(s->data, buf + to_end - sizeof(uint16_t), real_len - to_end);
377         }
378         else
379         {
380             /* The message length wraps around the end of the buffer */
381             memcpy(s->data + iptr, (uint8_t *) &lenx, to_end);
382             memcpy(s->data, ((uint8_t *) &lenx) + to_end, sizeof(uint16_t) - to_end);
383             memcpy(s->data + sizeof(uint16_t) - to_end, buf, len);
384         }
385         new_iptr = real_len - to_end;
386     }
387     /*endif*/
388     /* Only change the pointer now we have really finished */
389     s->iptr = new_iptr;
390     return len;
391 }
392 /*- End of function --------------------------------------------------------*/
393 
queue_init(queue_state_t * s,int len,int flags)394 queue_state_t *queue_init(queue_state_t *s, int len, int flags)
395 {
396     if (s == NULL)
397     {
398         if ((s = (queue_state_t *) malloc(sizeof(*s) + len + 1)) == NULL)
399             return NULL;
400     }
401     s->iptr =
402     s->optr = 0;
403     s->flags = flags;
404     s->len = len + 1;
405     return s;
406 }
407 /*- End of function --------------------------------------------------------*/
408 
queue_free(queue_state_t * s)409 int queue_free(queue_state_t *s)
410 {
411     free(s);
412     return 0;
413 }
414 /*- End of function --------------------------------------------------------*/
415 /*- End of file ------------------------------------------------------------*/
416