source: roaraudio/libroar/buffer.c @ 5299:5fbc169961b9

Last change on this file since 5299:5fbc169961b9 was 5299:5fbc169961b9, checked in by phi, 12 years ago

changed prototype of roar_buffer_moveinto() to avoid use-after-free bugs

File size: 20.0 KB
RevLine 
[0]1//buffer.c:
2
[690]3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
[690]5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[690]23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
[0]36#include "libroar.h"
37
[4516]38struct roar_buffer_ring {
39 size_t read_pos;
40 size_t write_pos;
41};
42
43struct roar_buffer {
44 size_t               refc;
45 size_t               len;
46 size_t               user_len;
47 int                  flags;
48 void               * data;
49 void               * user_data;
50 union {
51  void                    * vp;
52  int32_t                   i32;
53  struct roar_buffer_ring   ring;
54 }                    meta;
[4901]55 int                  type;
[4516]56 struct roar_buffer * next;
57};
[1215]58
[5011]59#define _ckbuf_free(m)  if ( buf == NULL || (m) ) { roar_err_set(ROAR_ERROR_FAULT); return -1; }
[5131]60#define _ckbuf(m)       if ( _ckmem_corruption(buf, (m)) == -1 ) return -1;
61
62// if we use the 'inline' keyword here the program segfaults. why?
63static int _ckmem_corruption(volatile struct roar_buffer * buf, int m) {
64 int flags;
65
66 ROAR_DBG("_ckmem_corruption(buf=%p) = ?", buf);
[5011]67
[5131]68 // we need to recheck here, why?
69 // gcc changes the order of the above macros. why?
70 // this is a strange world.
71 if ( buf == NULL || m ) {
72  ROAR_DBG("_ckmem_corruption(buf=%p) = -1 // FAULT", buf);
73  roar_err_set(ROAR_ERROR_FAULT);
74  return -1;
75 }
76
77 ROAR_DBG("_ckmem_corruption(buf=%p) = ?", buf);
78
79 flags = buf->flags & (ROAR_BUFFER_FLAG_USEABLE|ROAR_BUFFER_FLAG_FREED);
[5011]80
81 ROAR_DBG("_ckmem_corruption(buf=%p{.flags=0x%.4x, ...} = ?", buf, buf->flags);
82
83 if ( flags == ROAR_BUFFER_FLAG_USEABLE ) {
84  // seems ok, continue with next check.
85 } else if ( flags == ROAR_BUFFER_FLAG_FREED ) {
86  roar_panic(ROAR_FATAL_ERROR_MEMORY_USED_AFTER_FREE, NULL);
87  roar_err_set(ROAR_ERROR_FAULT);
88  return -1;
89 } else {
90  roar_panic(ROAR_FATAL_ERROR_MEMORY_CORRUPTION, NULL);
91  roar_err_set(ROAR_ERROR_BADCKSUM);
92  return -1;
93 }
94
95 if ( buf->refc == 0 ) {
96  roar_panic(ROAR_FATAL_ERROR_MEMORY_CORRUPTION, NULL);
[5299]97  roar_err_set(ROAR_ERROR_FAULT);
98  return -1;
[5011]99 }
100
101 return 0;
102}
[4905]103
[3764]104int roar_buffer_new_data (struct roar_buffer ** buf, size_t len, void ** data) {
105 void * bufdata;
[4905]106 int err;
[3764]107
108 if ((bufdata = roar_mm_malloc(len)) == NULL) {
[1215]109  return -1;
110 }
111
[3764]112 if ( roar_buffer_new_no_ma(buf, len, bufdata) == -1 ) {
[4905]113  err = roar_error;
[3764]114  roar_mm_free(bufdata);
[4905]115  roar_err_set(err);
[1215]116  return -1;
117 }
118
119 if ( roar_buffer_set_flag(*buf, ROAR_BUFFER_FLAG_NOFREE, ROAR_BUFFER_RESET) == -1 ) {
[4905]120  err = roar_error;
[1215]121  roar_buffer_free(*buf);
[3764]122  roar_mm_free(bufdata);
[4905]123  roar_err_set(err);
[1215]124  return -1;
125 }
126
[3764]127 if ( data != NULL )
128  *data = bufdata;
129
[1215]130 return 0;
131}
132
133int roar_buffer_new_no_ma(struct roar_buffer ** buf, size_t len, void * data) { // no internal malloc
[0]134 struct roar_buffer * new;
135
136 ROAR_DBG("buffer_new(buf=%p, len=%i) = ?", buf, len);
137
[5011]138 _ckbuf_free(data == NULL)
[1215]139
[2976]140 if ((new = roar_mm_malloc(sizeof(struct roar_buffer))) == NULL) {
[0]141  *buf = NULL;
142  return -1;
143 }
144
[4901]145 new->refc      =  1;
[4522]146
[1215]147 new->data      = data;
148
[5011]149 new->flags     = ROAR_BUFFER_FLAG_NONE|ROAR_BUFFER_FLAG_NOFREE|ROAR_BUFFER_FLAG_USEABLE;
[4901]150 new->type      = -1;
[0]151
152 new->user_data = new->data;
153
154 new->next      = NULL;
155
156 new->len       = len;
157 new->user_len  = len;
158 *buf           = new;
159
160 ROAR_DBG("buffer_new(buf=%p, len=%i): New buffer at %p", buf, len, new);
161
162 return 0;
163}
164
[4522]165int roar_buffer_ref      (struct roar_buffer *  buf) {
[4905]166 _ckbuf(0)
[4522]167
168 buf->refc++;
169
170 return 0;
171}
172
173int roar_buffer_unref     (struct roar_buffer * buf) {
[5011]174 struct roar_buffer * next, * cur;
175 int flags;
176
177 ROAR_DBG("roar_buffer_unref(buf=%p) = ?", buf);
178
179 _ckbuf_free(0)
180
181 ROAR_DBG("roar_buffer_unref(buf=%p) = ?", buf);
[0]182
[5011]183 flags = buf->flags & (ROAR_BUFFER_FLAG_USEABLE|ROAR_BUFFER_FLAG_FREED);
184 if ( flags == ROAR_BUFFER_FLAG_FREED ) {
185  roar_panic(ROAR_FATAL_ERROR_MEMORY_DOUBLE_FREE, NULL);
186 }
187
[5131]188 _ckmem_corruption(buf, 0);
[5011]189
190 ROAR_DBG("roar_buffer_unref(buf=%p) = ?", buf);
[0]191
[4522]192 if ( buf->refc == 0 ) {
193  ROAR_WARN("roar_buffer_unref(buf=%p): Ref counter is wrong. assuming one.");
194  buf->refc = 1;
[4973]195  roar_panic(ROAR_FATAL_ERROR_MEMORY_CORRUPTION, NULL);
[4522]196 }
197
198 buf->refc--;
199
[5011]200 if ( buf->refc ) {
201  ROAR_DBG("roar_buffer_unref(buf=%p) = 0", buf);
[4522]202  return 0;
[0]203 }
204
[5011]205 ROAR_DBG("roar_buffer_unref(buf=%p) = ?", buf);
206
207 cur = buf->next;
208 while (cur != NULL) {
209  flags = cur->flags & (ROAR_BUFFER_FLAG_USEABLE|ROAR_BUFFER_FLAG_FREED);
210  if ( flags == ROAR_BUFFER_FLAG_FREED ) {
211   roar_panic(ROAR_FATAL_ERROR_MEMORY_DOUBLE_FREE, NULL);
212  }
213
214  ROAR_DBG("roar_buffer_unref(buf=%p) = ?", buf);
215
[5131]216  _ckmem_corruption(cur, 0);
[5011]217
218  if ( roar_buffer_get_flag(cur, ROAR_BUFFER_FLAG_NOFREE) != 1 )
219   roar_mm_free(cur->data);
220
221  cur->flags = ROAR_BUFFER_FLAG_FREED;
222  next = cur->next;
223  roar_mm_free(cur);
224  cur = next;
225 }
226
227 ROAR_DBG("roar_buffer_unref(buf=%p) = ?", buf);
228
229 if ( !(buf->flags & ROAR_BUFFER_FLAG_NOFREE) )
[2976]230  roar_mm_free(buf->data);
[1215]231
[5011]232 ROAR_DBG("roar_buffer_unref(buf=%p): setting flags = ROAR_BUFFER_FLAG_FREED", buf);
233 buf->flags = ROAR_BUFFER_FLAG_FREED;
234
[2976]235 roar_mm_free(buf);
[0]236
[5011]237 ROAR_DBG("roar_buffer_unref(buf=%p) = 0", buf);
[0]238 return 0;
239}
240
241int roar_buffer_delete   (struct roar_buffer * buf, struct roar_buffer ** next) {
242 if ( buf == NULL ) {
243  if ( next != NULL )
244   *next = NULL;
[4905]245  roar_err_set(ROAR_ERROR_FAULT);
[0]246  return -1;
247 }
248
249 ROAR_DBG("buffer_delete(buf=%p, next=%p) = ?", buf, next);
250
251 if ( next != NULL )
252  *next = buf->next;
253
[2976]254 if ( roar_buffer_get_flag(buf, ROAR_BUFFER_FLAG_NOFREE) != 1 )
255  roar_mm_free(buf->data);
256
257 roar_mm_free(buf);
[0]258
259 ROAR_DBG("buffer_delete(buf=%p, next=%p) = 0", buf, next);
260 return 0;
261}
262
[5298]263int roar_buffer_next     (struct roar_buffer ** buf) {
264 return roar_buffer_delete(*buf, buf);
265}
266
[0]267int roar_buffer_add      (struct roar_buffer * buf, struct roar_buffer *  next) {
[5299]268 return roar_buffer_moveinto(buf, &next);
[5298]269}
270
[5299]271int roar_buffer_moveinto (struct roar_buffer * buf, struct roar_buffer ** next) {
[1953]272 unsigned int deep = 0;
273
[5299]274 _ckbuf(next == NULL || _ckmem_corruption(*next, 0))
[0]275
276 ROAR_DBG("buffer_add(buf=%p, next=%p) = ?", buf, next);
[5299]277 ROAR_DBG("buffer_add(buf=%p, next=%p): *next=%p", buf, next, *next);
[0]278
[4905]279 if ( buf->flags & ROAR_BUFFER_FLAG_RING ) {
280  roar_err_set(ROAR_ERROR_INVAL);
[3020]281  return -1;
[4905]282 }
[3020]283
[5299]284 if ( buf == *next ) {
[1953]285  ROAR_ERR("buffer_add(*): both pointer are of the same destination, This is a error in the application");
[4905]286  roar_err_set(ROAR_ERROR_INVAL);
[1953]287  return -1;
288 }
289
[0]290 while ( buf->next != NULL ) {
[302]291  ROAR_DBG("buffer_add(*): buf=%p, next=%p (len=%i)", buf, buf->next, buf->user_len);
[0]292//  ROAR_DBG("buffer_add(): buf=%p, buf->next=%p", buf, buf->next);
293  buf = buf->next;
[1953]294  deep++;
295
[5299]296  if ( buf == *next ) {
[1953]297   ROAR_ERR("buffer_add(*): Can not add buffer: loop detected at deep %u. This is a error in the application", deep);
[4905]298   // why don't we return here?
[1953]299  }
[0]300 }
301
[5299]302 buf->next = *next;
[0]303
[1953]304 ROAR_DBG("buffer_add(*): adding buffer at deep %u", deep);
305
[5299]306 *next = NULL;
307
[0]308 return 0;
309}
310
311int roar_buffer_get_next (struct roar_buffer *  buf, struct roar_buffer ** next) {
[4905]312 _ckbuf(0)
[0]313
314 *next = buf->next;
315
316 return 0;
317}
318
[3020]319int roar_buffer_ring_new (struct roar_buffer ** buf, size_t len, int free_running) {
320 struct roar_buffer * n;
321
[5011]322 _ckbuf_free(0)
[4905]323
324 if ( len == 0 ) {
325  roar_err_set(ROAR_ERROR_RANGE);
[3020]326  return -1;
[4905]327 }
[3020]328
329 // just to be sure:
330 *buf = NULL;
331
332 if ( roar_buffer_new(&n, len) == -1 )
333  return -1;
334
335 n->flags |= ROAR_BUFFER_FLAG_RING;
336
337 if ( free_running )
338  n->flags |= ROAR_BUFFER_FLAG_FREE_RUNNING;
339
340 n->meta.ring.read_pos  = 0;
341 n->meta.ring.write_pos = 0;
342
343 memset(n->data, 0, n->len);
344
345 *buf = n;
346
347 return 0;
348}
349
[0]350int roar_buffer_get_data (struct roar_buffer *  buf, void   ** data) {
[4905]351 _ckbuf(0)
[0]352
353 *data = buf->user_data;
354
355 return 0;
356}
357
358int roar_buffer_set_offset (struct roar_buffer *  buf, size_t off) {
[4905]359 _ckbuf(0)
360
361 if ( off > buf->user_len ) {
362  roar_err_set(ROAR_ERROR_RANGE);
[0]363  return -1;
[4905]364 }
[0]365
366 buf->user_len  -= off;
367 buf->user_data += off;
368
369 return 0;
370}
371
[904]372int roar_buffer_shift_out (struct roar_buffer ** buf, void * data, size_t * len) {
373 size_t todo, cl;
374 struct roar_buffer * cur;
375 void * cd;
376
[5011]377 _ckbuf_free(len == NULL || data == NULL);
[904]378
[996]379 if ( *buf == NULL ) {
380  ROAR_DBG("roar_buffer_shift_out(buf=%p, data=%p, len={%lu}) = -1 // Invalid pointer to buffer ring", buf, data, (unsigned long)len);
[4905]381  roar_err_set(ROAR_ERROR_FAULT);
[904]382  return -1;
[996]383 }
[904]384
385 todo = *len;
386 cur  = *buf;
387
388 *len = 0;
389
[2066]390 while (todo && cur != NULL) {
[904]391  ROAR_DBG("roar_buffer_shift_out(*): todo=%u, cur=%p", (unsigned int) todo, cur);
392
[5131]393  _ckmem_corruption(cur, 0);
[5013]394
[904]395  if ( roar_buffer_get_len(cur, &cl) == -1 )
396   return -1;
397
398  if ( cl > todo ) {
399   if ( roar_buffer_get_data(cur, &cd) == -1 )
400    return -1;
401
402   cl = todo;
403
404   memcpy(data, cd, cl);
405   todo -= cl;
406   data += cl;
407   *len += cl;
408
409   if ( roar_buffer_set_offset(cur, cl) == -1 )
410    return -1;
411  } else {
412   if ( roar_buffer_get_data(cur, &cd) == -1 )
413    return -1;
414
415   memcpy(data, cd, cl);
416   todo -= cl;
417   data += cl;
418   *len += cl;
419
420   if ( roar_buffer_next(&cur) == -1 )
421    return -1;
422  }
423
424/*
425  if ( cur == NULL )
426   break;
427*/
428 }
429
430 *buf = cur;
431
[996]432 return 0;
[904]433}
434
[0]435int roar_buffer_set_meta (struct roar_buffer * buf, void *  meta) {
[4905]436 _ckbuf(0)
[0]437
[2333]438 buf->meta.vp = meta;
[0]439
440 return 0;
441}
442
443int roar_buffer_get_meta (struct roar_buffer * buf, void ** meta) {
[4905]444 _ckbuf(meta == NULL)
[2333]445
446 *meta = buf->meta.vp;
447
448 return 0;
449}
450
451int roar_buffer_set_meta_i32(struct roar_buffer *  buf, int32_t    meta) {
[4905]452 _ckbuf(0)
[0]453
[2333]454 buf->meta.i32 = meta;
455
456 return 0;
457}
458
459int roar_buffer_get_meta_i32(struct roar_buffer *  buf, int32_t *  meta) {
[4905]460 _ckbuf(meta == NULL)
[2333]461
462 *meta = buf->meta.i32;
[0]463
464 return 0;
465}
466
[4901]467int roar_buffer_set_type    (struct roar_buffer *  buf, int        type) {
[4905]468 _ckbuf(0)
[4901]469
[4903]470 switch (type) {
471  case ROAR_VIO_DFT_RAW:
472  case ROAR_VIO_DFT_PACKET:
473  case ROAR_VIO_DFT_UNFRAMED:
[4988]474  case ROAR_VIO_DFT_OGG_PACKET:
475  case ROAR_VIO_DFT_OGG_PAGE:
[4903]476   break;
477  default:
[4905]478    roar_err_set(ROAR_ERROR_NOTSUP);
[4903]479    return -1;
480 }
481
[4901]482 buf->type = type;
483
484 return 0;
485}
486
487int roar_buffer_get_type    (struct roar_buffer *  buf, int     *  type) {
[4905]488 _ckbuf(type == NULL)
[4901]489
490 *type = buf->type;
491
492 return 0;
493}
494
[0]495int roar_buffer_set_len  (struct roar_buffer *  buf, size_t    len) {
[2334]496 size_t   totlen;
497 void   * newbuf;
498
[4905]499 _ckbuf(0)
[0]500
[3032]501 // handle specal case where user length is zero:
502 if ( len && !buf->user_len ) {
503  buf->user_data = buf->data;
504  buf->user_len  = buf->len;
505 }
506
[2334]507 if ( len > buf->user_len ) {
[3021]508  // we can only enlage a buffer if it's one of our own memory segments
[4905]509  if ( buf->flags & ROAR_BUFFER_FLAG_NOFREE )  {
510   roar_err_set(ROAR_ERROR_NOTSUP);
[3021]511   return -1;
[4905]512  }
[3021]513
[4989]514  totlen = (buf->len - buf->user_len) + len;
[3021]515  newbuf = roar_mm_realloc(buf->data, totlen);
[2334]516  if ( newbuf == NULL )
517   return -1;
518
[4988]519  buf->user_data = newbuf + (buf->user_data - buf->data);
[4989]520  buf->user_len = len;
[2334]521  buf->data = newbuf;
[4989]522  buf->len  = totlen;
[2334]523 } else {
524  buf->user_len = len;
525 }
[0]526
527 return 0;
528}
529
530int roar_buffer_get_len  (struct roar_buffer *  buf, size_t *  len) {
[4905]531 _ckbuf(0)
[0]532
533 *len = buf->user_len;
534
535 return 0;
536}
537
[1215]538int roar_buffer_set_flag (struct roar_buffer *  buf, int flag, int reset) {
[4905]539 _ckbuf(0)
[1215]540
541 buf->flags |= flag;
542
543 if ( reset )
544  buf->flags -= flag;
545
546 return 0;
547}
548
549int roar_buffer_get_flag (struct roar_buffer *  buf, int flag) {
[4905]550 _ckbuf(0)
[1215]551
552 return buf->flags & flag;
553}
554
[46]555int roar_buffer_duplicate (struct roar_buffer *  buf, struct roar_buffer ** copy) {
556 struct roar_buffer *  cur = buf;
557 struct roar_buffer *  new;
[48]558 void * od, * nd;
[4905]559 int err;
560
561 _ckbuf(copy == NULL)
[46]562
563 *copy = NULL;
564
[5111]565 // TODO:  This function does not handle ring buffers.
566 // FIXME: This function does not error out in case of wrong buffer type in buf.
567 // TODO:  This function does not handle buffer meta data.
568
[4905]569 while (cur != NULL) {
[46]570  if ( roar_buffer_new(&new, cur->user_len) == -1 ) {
[4905]571   err = roar_error;
[46]572   roar_buffer_free(*copy);
[4905]573   roar_err_set(err);
[46]574   return -1;
575  }
576
577  if ( *copy == NULL )
578   *copy = new;
579
[5111]580  _LIBROAR_IGNORE_RET(roar_buffer_get_data(cur, &od));
581  _LIBROAR_IGNORE_RET(roar_buffer_get_data(new, &nd));
[48]582  memcpy(nd, od, cur->user_len);
583
[5111]584  _LIBROAR_IGNORE_RET(roar_buffer_add(*copy, new));
[46]585
586  cur = cur->next;
587 }
[4905]588
[46]589 return 0;
590}
591
[7]592int roar_buffer_ring_stats (struct roar_buffer *  buf, struct roar_buffer_stats * stats) {
[5131]593 ROAR_DBG("roar_buffer_ring_stats(buf=%p, stats=%p) = ?", buf, stats);
594
[4905]595 _ckbuf(0)
[7]596
[5131]597 ROAR_DBG("roar_buffer_ring_stats(buf=%p, stats=%p) = ?", buf, stats);
598
[7]599 stats->parts        = 0;
600 stats->bytes        = 0;
601 stats->memory_usage = 0;
602
[4905]603 while (buf != NULL ) {
[7]604  stats->parts++;
605  stats->bytes        += buf->user_len;
606  stats->memory_usage += buf->len + sizeof(struct roar_buffer);
607  buf = buf->next;
608 }
609
610 return 0;
611}
612
[3020]613int roar_buffer_ring_read  (struct roar_buffer *  buf, void * data, size_t * len) {
[4615]614 struct roar_buffer_ring * ring;
615 size_t havelen;
616 size_t done;
617 size_t tmp;
618
[4905]619 _ckbuf(len == NULL)
620
[3020]621 if ( buf == NULL || len == NULL )
622  return -1;
623
[4905]624 if ( data == NULL && *len != 0 ) {
625  roar_err_set(ROAR_ERROR_FAULT);
[3020]626  return -1;
[4905]627 }
[3020]628
[4905]629 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) ) {
630  roar_err_set(ROAR_ERROR_TYPEMM);
[3020]631  return -1;
[4905]632 }
[3020]633
634 if ( *len == 0 )
635  return 0;
636
637 // we may handle this later:
[4905]638 if ( *len > buf->user_len ) {
639  roar_err_set(ROAR_ERROR_NOTSUP);
[3020]640  return -1;
[4905]641 }
[3020]642
[4615]643 if ( (buf->flags & ROAR_BUFFER_FLAG_FREE_RUNNING) ) {
644  if ( buf->meta.ring.read_pos >= buf->user_len )
645   buf->meta.ring.read_pos -= buf->user_len;
[3020]646
[4615]647  if ( (*len + buf->meta.ring.read_pos) > buf->user_len ) {
648   // wraped mode:
649   memcpy(data, buf->user_data+buf->meta.ring.read_pos, buf->user_len - buf->meta.ring.read_pos);
650   memcpy(data, buf->user_data, *len + buf->meta.ring.read_pos - buf->user_len);
651 
652   buf->meta.ring.read_pos += *len;
653   buf->meta.ring.read_pos -= buf->user_len;
654   return 0;
655  } else {
656   // unwarped mode:
657   memcpy(data, buf->user_data+buf->meta.ring.read_pos, *len);
658   buf->meta.ring.read_pos += *len;
659   return 0;
660  }
661 } else {
662  ring = &(buf->meta.ring);
663
664  if ( ring->read_pos == ring->write_pos ) {
665   *len = 0;
666   return 0;
667  } else if ( ring->read_pos < ring->write_pos ) {
668   havelen = ring->write_pos - ring->read_pos;
669
670   if ( havelen > *len )
671    havelen = *len;
672
673   memcpy(data, buf->user_data+ring->read_pos, havelen);
674   ring->read_pos += havelen;
[3020]675
[4615]676   *len = havelen;
677   return 0;
678  } else { // write_pos < read_pos
679   done = 0;
680
681   // first pass: use data up to end of buffer
682
683   havelen = buf->user_len - ring->read_pos;
684
685   if ( havelen > *len )
686    havelen = *len;
687
688   memcpy(data, buf->user_data+ring->read_pos, havelen);
689   ring->read_pos += havelen;
690
691   done += havelen;
692
693   if ( ring->read_pos == buf->user_len ) {
694    ring->read_pos = 0;
695   }
696
697   // second pass: use data from strat of buffer to write pointer
698
699   if ( *len > done ) {
700    tmp = *len - done;
701    if ( roar_buffer_ring_read(buf, data+done, &tmp) == 0 ) {
702     done += tmp;
703    }
704   }
705
706   *len = done;
707   return 0;
708  }
[3020]709 }
710
[4905]711 roar_err_set(ROAR_ERROR_UNKNOWN);
[3020]712 return -1;
713}
714
715int roar_buffer_ring_write (struct roar_buffer *  buf, void * data, size_t * len) {
[4624]716 struct roar_buffer_ring * ring;
717 size_t havelen;
718 size_t done;
719 size_t tmp;
720
[4625]721 ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p) = ?", buf, data, len);
722
[4905]723 _ckbuf(len == NULL)
[3020]724
[4905]725 if ( data == NULL && *len != 0 ) {
726  roar_err_set(ROAR_ERROR_FAULT);
[3020]727  return -1;
[4905]728 }
[3020]729
[4905]730 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) ) {
731  roar_err_set(ROAR_ERROR_TYPEMM);
[3020]732  return -1;
[4905]733 }
[3020]734
735 if ( *len == 0 )
736  return 0;
737
738 // we may handle this later:
[4905]739 if ( *len > buf->user_len ) {
740  roar_err_set(ROAR_ERROR_NOTSUP);
[3020]741  return -1;
[4905]742 }
[3020]743
[4615]744 if ( (buf->flags & ROAR_BUFFER_FLAG_FREE_RUNNING) ) {
745  if ( buf->meta.ring.write_pos >= buf->user_len )
746   buf->meta.ring.write_pos -= buf->user_len;
[3020]747
[4615]748  if ( (*len + buf->meta.ring.write_pos) > buf->user_len ) {
749   // wraped mode:
750   memcpy(buf->user_data+buf->meta.ring.write_pos, data, buf->user_len - buf->meta.ring.write_pos);
751   memcpy(buf->user_data, data, *len + buf->meta.ring.write_pos - buf->user_len);
[3020]752
[4615]753   buf->meta.ring.write_pos += *len;
754   buf->meta.ring.write_pos -= buf->user_len;
755   return 0;
756  } else {
757   // unwarped mode:
758   memcpy(buf->user_data+buf->meta.ring.write_pos, data, *len);
759   buf->meta.ring.write_pos += *len;
760   return 0;
761  }
[3020]762 } else {
[4624]763  ring = &(buf->meta.ring);
764  done = 0;
765
766  ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p): write_pos=%u, read_pos=%u, user_len=%u", buf, data, len, (unsigned int)ring->write_pos, (unsigned int)ring->read_pos, (unsigned int)buf->user_len);
767
768  if ( ring->write_pos >= ring->read_pos ) {
[4625]769   ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p) = ?", buf, data, len);
770
[4624]771   havelen = buf->user_len - ring->write_pos;
772
773   if ( ring->read_pos == 0 )
774    havelen--;
775
776   if ( havelen > *len )
777    havelen = *len;
778
779   memcpy(buf->user_data+ring->write_pos, data, havelen);
780
781   done += havelen;
782   ring->write_pos += havelen;
783
784   if ( ring->write_pos == buf->user_len )
785    ring->write_pos = 0;
786
787   if ( *len > done && ring->read_pos != 0 ) {
788    tmp = *len - done;
789    if ( roar_buffer_ring_write(buf, data+done, &tmp) == 0 ) {
790     done += tmp;
791    }
792   }
793
794   *len = done;
[4625]795   ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p) = 0", buf, data, len);
[4624]796   return 0;
797  } else {
[4625]798   ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p) = ?", buf, data, len);
799
[4624]800   // test for buffer-is-full:
801   if ( (ring->write_pos + 1) == ring->read_pos ) {
802    *len = 0;
[4625]803    ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p) = 0", buf, data, len);
[4624]804    return 0;
805   }
806
[4625]807   ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p) = ?", buf, data, len);
808
[4624]809   havelen = ring->read_pos - ring->write_pos - 1;
810
811   if ( havelen > *len )
812    havelen = *len;
813
814   memcpy(buf->user_data+ring->write_pos, data, havelen);
815
[4625]816   ring->write_pos += havelen;
[4624]817   *len = havelen;
[4625]818
819   ROAR_DBG("roar_buffer_ring_write(buf=%p, data=%p, len=%p) = 0", buf, data, len);
[4624]820   return 0;
821  }
[3020]822 }
823
[4905]824 roar_err_set(ROAR_ERROR_UNKNOWN);
[3020]825 return -1;
826}
827
[4625]828int roar_buffer_ring_avail(struct roar_buffer *  buf, size_t * readlen, size_t * writelen) {
829 struct roar_buffer_ring * ring;
830 size_t have;
831
[4905]832 _ckbuf(0)
[4625]833
[4905]834 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) ) {
835  roar_err_set(ROAR_ERROR_TYPEMM);
[4625]836  return -1;
[4905]837 }
[4625]838
839 ring = &(buf->meta.ring);
840
841 ROAR_DBG("roar_buffer_ring_avail(buf=%p, readlen=%p, writelen=%p) = ?", buf, readlen, writelen);
842
843 if ( readlen != NULL ) {
844  have = 0;
845
846  if ( ring->write_pos >= ring->read_pos ) {
847   have  = ring->write_pos - ring->read_pos;
848  } else {
849   have  = buf->user_len - ring->read_pos;
850   have += ring->write_pos;
851   have -= 1;
852  }
853
854  *readlen = have;
855  ROAR_DBG("roar_buffer_ring_avail(buf=%p, readlen=%p, writelen=%p): readlen=%llu", buf, readlen, writelen, (unsigned long long int)have);
856 }
857
858 if ( writelen != NULL ) {
859  have = 0;
860
861  if ( ring->read_pos > ring->write_pos ) {
862   have  = ring->read_pos - ring->write_pos - 1;
863  } else {
864   have  = buf->user_len - ring->write_pos;
865   have += ring->read_pos;
866   have -= 1;
867  }
868
869  *writelen = have;
870  ROAR_DBG("roar_buffer_ring_avail(buf=%p, readlen=%p, writelen=%p): readlen=%llu", buf, readlen, writelen, (unsigned long long int)have);
871 }
872
873 ROAR_DBG("roar_buffer_ring_avail(buf=%p, readlen=%p, writelen=%p) = 0", buf, readlen, writelen);
874
875 return 0;
876}
877
[4629]878int roar_buffer_ring_reset(struct roar_buffer *  buf) {
[4905]879 _ckbuf(0)
[4629]880
[4905]881 if ( !(buf->flags & ROAR_BUFFER_FLAG_RING) ) {
882  roar_err_set(ROAR_ERROR_TYPEMM);
[4629]883  return -1;
[4905]884 }
[4629]885
886 buf->meta.ring.read_pos = buf->meta.ring.write_pos = 0;
887
888 return 0;
889}
890
[0]891//ll
Note: See TracBrowser for help on using the repository browser.