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 
26 /*! \file */
27 
28 #if defined(HAVE_CONFIG_H)
29 #include "config.h"
30 #endif
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <time.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <inttypes.h>
38 #if defined(HAVE_STDBOOL_H)
39 #include <stdbool.h>
40 #else
41 #include "spandsp/stdbool.h"
42 #endif
43 #if defined(HAVE_STDATOMIC_H)
44 #include <stdatomic.h>
45 #endif
46 #include <sys/types.h>
47 
48 #define SPANDSP_FULLY_DEFINE_QUEUE_STATE_T
49 #include "spandsp/telephony.h"
50 #include "spandsp/alloc.h"
51 #include "spandsp/queue.h"
52 
53 #include "spandsp/private/queue.h"
54 
queue_empty(queue_state_t * s)55 SPAN_DECLARE(bool) queue_empty(queue_state_t *s)
56 {
57     return (s->iptr == s->optr);
58 }
59 /*- End of function --------------------------------------------------------*/
60 
queue_free_space(queue_state_t * s)61 SPAN_DECLARE(int) queue_free_space(queue_state_t *s)
62 {
63     int len;
64 
65     if ((len = s->optr - s->iptr - 1) < 0)
66         len += s->len;
67     /*endif*/
68     return len;
69 }
70 /*- End of function --------------------------------------------------------*/
71 
queue_contents(queue_state_t * s)72 SPAN_DECLARE(int) queue_contents(queue_state_t *s)
73 {
74     int len;
75 
76     if ((len = s->iptr - s->optr) < 0)
77         len += s->len;
78     /*endif*/
79     return len;
80 }
81 /*- End of function --------------------------------------------------------*/
82 
queue_flush(queue_state_t * s)83 SPAN_DECLARE(void) queue_flush(queue_state_t *s)
84 {
85     s->optr = s->iptr;
86 }
87 /*- End of function --------------------------------------------------------*/
88 
queue_view(queue_state_t * s,uint8_t * buf,int len)89 SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len)
90 {
91     int real_len;
92     int to_end;
93     int iptr;
94     int optr;
95 
96     /* Snapshot the values (although only iptr should be changeable during this processing) */
97     iptr = s->iptr;
98     optr = s->optr;
99     if ((real_len = iptr - optr) < 0)
100         real_len += s->len;
101     /*endif*/
102     if (real_len < len)
103     {
104         if (s->flags & QUEUE_READ_ATOMIC)
105             return -1;
106         /*endif*/
107     }
108     else
109     {
110         real_len = len;
111     }
112     /*endif*/
113     if (real_len == 0)
114         return 0;
115     /*endif*/
116     to_end = s->len - optr;
117     if (iptr < optr  &&  to_end < real_len)
118     {
119         /* A two step process */
120         if (buf)
121         {
122             memcpy(buf, &s->data[optr], to_end);
123             memcpy(&buf[to_end], s->data, real_len - to_end);
124         }
125         /*endif*/
126     }
127     else
128     {
129         /* A one step process */
130         if (buf)
131             memcpy(buf, &s->data[optr], real_len);
132         /*endif*/
133     }
134     /*endif*/
135     return real_len;
136 }
137 /*- End of function --------------------------------------------------------*/
138 
queue_read(queue_state_t * s,uint8_t * buf,int len)139 SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len)
140 {
141     int real_len;
142     int to_end;
143     int new_optr;
144     int iptr;
145     int optr;
146 
147     /* Snapshot the values (although only iptr should be changeable during this processing) */
148     iptr = s->iptr;
149     optr = s->optr;
150     if ((real_len = iptr - optr) < 0)
151         real_len += s->len;
152     /*endif*/
153     if (real_len < len)
154     {
155         if (s->flags & QUEUE_READ_ATOMIC)
156             return -1;
157         /*endif*/
158     }
159     else
160     {
161         real_len = len;
162     }
163     /*endif*/
164     if (real_len == 0)
165         return 0;
166     /*endif*/
167     to_end = s->len - optr;
168     if (iptr < optr  &&  to_end < real_len)
169     {
170         /* A two step process */
171         if (buf)
172         {
173             memcpy(buf, &s->data[optr], to_end);
174             memcpy(&buf[to_end], s->data, real_len - to_end);
175         }
176         /*endif*/
177         new_optr = real_len - to_end;
178     }
179     else
180     {
181         /* A one step process */
182         if (buf)
183             memcpy(buf, &s->data[optr], real_len);
184         /*endif*/
185         new_optr = optr + real_len;
186         if (new_optr >= s->len)
187             new_optr = 0;
188         /*endif*/
189     }
190     /*endif*/
191     /* Only change the pointer now we have really finished */
192     s->optr = new_optr;
193     return real_len;
194 }
195 /*- End of function --------------------------------------------------------*/
196 
queue_read_byte(queue_state_t * s)197 SPAN_DECLARE(int) queue_read_byte(queue_state_t *s)
198 {
199     int real_len;
200     int iptr;
201     int optr;
202     int byte;
203 
204     /* Snapshot the values (although only iptr should be changeable during this processing) */
205     iptr = s->iptr;
206     optr = s->optr;
207     if ((real_len = iptr - optr) < 0)
208         real_len += s->len;
209     /*endif*/
210     if (real_len < 1)
211         return -1;
212     /*endif*/
213     byte = s->data[optr];
214     if (++optr >= s->len)
215         optr = 0;
216     /*endif*/
217     /* Only change the pointer now we have really finished */
218     s->optr = optr;
219     return byte;
220 }
221 /*- End of function --------------------------------------------------------*/
222 
queue_write(queue_state_t * s,const uint8_t * buf,int len)223 SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len)
224 {
225     int real_len;
226     int to_end;
227     int new_iptr;
228     int iptr;
229     int optr;
230 
231     /* Snapshot the values (although only optr should be changeable during this processing) */
232     iptr = s->iptr;
233     optr = s->optr;
234 
235     if ((real_len = optr - iptr - 1) < 0)
236         real_len += s->len;
237     /*endif*/
238     if (real_len < len)
239     {
240         if (s->flags & QUEUE_WRITE_ATOMIC)
241             return -1;
242         /*endif*/
243     }
244     else
245     {
246         real_len = len;
247     }
248     /*endif*/
249     if (real_len == 0)
250         return 0;
251     /*endif*/
252     to_end = s->len - iptr;
253     if (iptr < optr  ||  to_end >= real_len)
254     {
255         /* A one step process */
256         memcpy(&s->data[iptr], buf, real_len);
257         new_iptr = iptr + real_len;
258         if (new_iptr >= s->len)
259             new_iptr = 0;
260         /*endif*/
261     }
262     else
263     {
264         /* A two step process */
265         memcpy(&s->data[iptr], buf, to_end);
266         memcpy(s->data, &buf[to_end], real_len - to_end);
267         new_iptr = real_len - to_end;
268     }
269     /*endif*/
270     /* Only change the pointer now we have really finished */
271     s->iptr = new_iptr;
272     return real_len;
273 }
274 /*- End of function --------------------------------------------------------*/
275 
queue_write_byte(queue_state_t * s,uint8_t byte)276 SPAN_DECLARE(int) queue_write_byte(queue_state_t *s, uint8_t byte)
277 {
278     int real_len;
279     int iptr;
280     int optr;
281 
282     /* Snapshot the values (although only optr should be changeable during this processing) */
283     iptr = s->iptr;
284     optr = s->optr;
285 
286     if ((real_len = optr - iptr - 1) < 0)
287         real_len += s->len;
288     /*endif*/
289     if (real_len < 1)
290     {
291         if (s->flags & QUEUE_WRITE_ATOMIC)
292             return -1;
293         /*endif*/
294         return 0;
295     }
296     /*endif*/
297     s->data[iptr] = byte;
298     if (++iptr >= s->len)
299         iptr = 0;
300     /*endif*/
301     /* Only change the pointer now we have really finished */
302     s->iptr = iptr;
303     return 1;
304 }
305 /*- End of function --------------------------------------------------------*/
306 
queue_state_test_msg(queue_state_t * s)307 SPAN_DECLARE(int) queue_state_test_msg(queue_state_t *s)
308 {
309     uint16_t lenx;
310 
311     if (queue_view(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t))
312         return -1;
313     /*endif*/
314     return lenx;
315 }
316 /*- End of function --------------------------------------------------------*/
317 
queue_read_msg(queue_state_t * s,uint8_t * buf,int len)318 SPAN_DECLARE(int) queue_read_msg(queue_state_t *s, uint8_t *buf, int len)
319 {
320     uint16_t lenx;
321 
322     /* If we assume the write message was atomic, this read message should be
323       safe when conducted in multiple chunks */
324     if (queue_read(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t))
325         return -1;
326     /*endif*/
327     /* If we got this far, the actual message chunk should be guaranteed to be
328        available */
329     if (lenx == 0)
330         return 0;
331     /*endif*/
332     if ((int) lenx > len)
333     {
334         len = queue_read(s, buf, len);
335         /* Discard the rest of the message */
336         queue_read(s, NULL, lenx - len);
337         return len;
338     }
339     /*endif*/
340     return queue_read(s, buf, lenx);
341 }
342 /*- End of function --------------------------------------------------------*/
343 
queue_write_msg(queue_state_t * s,const uint8_t * buf,int len)344 SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len)
345 {
346     int real_len;
347     int to_end;
348     int new_iptr;
349     int iptr;
350     int optr;
351     uint16_t lenx;
352 
353     /* Snapshot the values (although only optr should be changeable during this processing) */
354     iptr = s->iptr;
355     optr = s->optr;
356 
357     if ((real_len = optr - iptr - 1) < 0)
358         real_len += s->len;
359     /*endif*/
360     if (real_len < len + (int) sizeof(uint16_t))
361         return -1;
362     /*endif*/
363     real_len = len + (int) sizeof(uint16_t);
364 
365     to_end = s->len - iptr;
366     lenx = (uint16_t) len;
367     if (iptr < optr  ||  to_end >= real_len)
368     {
369         /* A one step process */
370         memcpy(&s->data[iptr], &lenx, sizeof(uint16_t));
371         memcpy(&s->data[iptr + sizeof(uint16_t)], buf, len);
372         new_iptr = iptr + real_len;
373         if (new_iptr >= s->len)
374             new_iptr = 0;
375         /*endif*/
376     }
377     else
378     {
379         /* A two step process */
380         if (to_end >= sizeof(uint16_t))
381         {
382             /* The actual message wraps around the end of the buffer */
383             memcpy(&s->data[iptr], &lenx, sizeof(uint16_t));
384             memcpy(&s->data[iptr + sizeof(uint16_t)], buf, to_end - sizeof(uint16_t));
385             memcpy(s->data, &buf[to_end - sizeof(uint16_t)], real_len - to_end);
386         }
387         else
388         {
389             /* The message length wraps around the end of the buffer */
390             memcpy(&s->data[iptr], (uint8_t *) &lenx, to_end);
391             memcpy(s->data, ((uint8_t *) &lenx) + to_end, sizeof(uint16_t) - to_end);
392             memcpy(&s->data[sizeof(uint16_t) - to_end], buf, len);
393         }
394         new_iptr = real_len - to_end;
395     }
396     /*endif*/
397     /* Only change the pointer now we have really finished */
398     s->iptr = new_iptr;
399     return len;
400 }
401 /*- End of function --------------------------------------------------------*/
402 
queue_init(queue_state_t * s,int len,int flags)403 SPAN_DECLARE(queue_state_t *) queue_init(queue_state_t *s, int len, int flags)
404 {
405     if (s == NULL)
406     {
407         if ((s = (queue_state_t *) span_alloc(sizeof(*s) + len + 1)) == NULL)
408             return NULL;
409     }
410     s->iptr =
411     s->optr = 0;
412     s->flags = flags;
413     s->len = len + 1;
414     return s;
415 }
416 /*- End of function --------------------------------------------------------*/
417 
queue_release(queue_state_t * s)418 SPAN_DECLARE(int) queue_release(queue_state_t *s)
419 {
420     return 0;
421 }
422 /*- End of function --------------------------------------------------------*/
423 
queue_free(queue_state_t * s)424 SPAN_DECLARE(int) queue_free(queue_state_t *s)
425 {
426     span_free(s);
427     return 0;
428 }
429 /*- End of function --------------------------------------------------------*/
430 /*- End of file ------------------------------------------------------------*/
431