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