1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_frab_list.c -- List of buffer for simple reading and writing
4 */
5
6#include <stddef.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/queue.h>
10
11#include "lsquic_frab_list.h"
12
13
14static void *
15fral_alloc (void *ctx, size_t size)
16{
17    return malloc(size);
18}
19
20
21static void
22fral_free (void *ctx, void *obj)
23{
24    free(obj);
25}
26
27
28void
29lsquic_frab_list_init (struct frab_list *fral, unsigned short buf_size,
30    void * (*alloc)(void *alloc_ctx, size_t size),
31    void (*free)(void *alloc_ctx, void *obj), void *alloc_ctx)
32{
33    TAILQ_INIT(&fral->fl_frabs);
34    fral->fl_alloc_ctx = alloc_ctx;
35    fral->fl_alloc     = alloc ? alloc : fral_alloc;
36    fral->fl_free      = free ? free : fral_free;
37    fral->fl_buf_size  = buf_size;
38    fral->fl_size      = 0;
39}
40
41
42void
43lsquic_frab_list_cleanup (struct frab_list *fral)
44{
45    struct frame_buf *frab, *next;
46
47    for (frab = TAILQ_FIRST(&fral->fl_frabs); frab; frab = next)
48    {
49        next = TAILQ_NEXT(frab, frab_next);
50        fral->fl_free(fral->fl_alloc_ctx, frab);
51    }
52}
53
54
55static struct frame_buf *
56fral_get_frab (struct frab_list *fral)
57{
58    struct frame_buf *frab;
59    frab = fral->fl_alloc(fral->fl_alloc_ctx, fral->fl_buf_size);
60    if (frab)
61    {
62        memset(frab, 0, sizeof(*frab));
63        frab->frab_buf_size = fral->fl_buf_size;
64    }
65    return frab;
66}
67
68
69int
70lsquic_frab_list_write (struct frab_list *fral, const void *buf, size_t bufsz)
71{
72    const unsigned char *p = buf;
73    const unsigned char *const end = p + bufsz;
74    struct frame_buf *frab;
75    unsigned ntowrite;
76
77    while (p < end)
78    {
79        frab = TAILQ_LAST(&fral->fl_frabs, frame_buf_head);
80        if (!(frab && (ntowrite = frab_left_to_write(frab)) > 0))
81        {
82            frab = fral_get_frab(fral);
83            if (!frab)
84                return -1;
85            TAILQ_INSERT_TAIL(&fral->fl_frabs, frab, frab_next);
86            ntowrite = frab_left_to_write(frab);
87        }
88        if ((ptrdiff_t) ntowrite > end - p)
89            ntowrite = end - p;
90        memcpy(frab_write_to(frab), p, ntowrite);
91        p += ntowrite;
92        frab->frab_size += ntowrite;
93    }
94
95    fral->fl_size += bufsz;
96    return 0;
97}
98
99
100size_t
101lsquic_frab_list_size (void *ctx)
102{
103    struct frab_list *fral = ctx;
104    return fral->fl_size;
105}
106
107
108size_t
109lsquic_frab_list_read (void *ctx, void *buf, size_t bufsz)
110{
111    struct frab_list *const fral = ctx;
112    unsigned char *p = buf;
113    unsigned char *const end = p + bufsz;
114    struct frame_buf *frab;
115    size_t ntocopy;
116
117    while (p < end && (frab = TAILQ_FIRST(&fral->fl_frabs)))
118    {
119        ntocopy = end - p;
120        if (ntocopy > (size_t) frab_left_to_read(frab))
121            ntocopy = frab_left_to_read(frab);
122        memcpy(p, frab->frab_buf + frab->frab_off, ntocopy);
123        fral->fl_size -= ntocopy;
124        frab->frab_off += ntocopy;
125        p += ntocopy;
126        if (frab->frab_off == frab->frab_size)
127        {
128            TAILQ_REMOVE(&fral->fl_frabs, frab, frab_next);
129            fral->fl_free(fral->fl_alloc_ctx, frab);
130        }
131    }
132
133    return p - (unsigned char *) buf;
134}
135
136
137size_t
138lsquic_frab_list_mem_used (const struct frab_list *fral)
139{
140    struct frame_buf *frab;
141    size_t size;
142
143    size = sizeof(*fral);
144    TAILQ_FOREACH(frab, &fral->fl_frabs, frab_next)
145        size += fral->fl_buf_size;
146
147    return size;
148}
149