blob: 662f404c03766e367ea921cc846f16d6f0818612 [file] [log] [blame]
Amaury Denoyelle1b5f77f2022-05-09 09:37:27 +02001#include <haproxy/ncbuf.h>
2
3#ifdef DEBUG_DEV
4# include <haproxy/bug.h>
5#else
6# include <stdio.h>
7# include <stdlib.h>
8
9# undef BUG_ON
10# define BUG_ON(x) if (x) { fprintf(stderr, "CRASH ON %s:%d\n", __func__, __LINE__); abort(); }
11
12# undef BUG_ON_HOT
13# define BUG_ON_HOT(x) if (x) { fprintf(stderr, "CRASH ON %s:%d\n", __func__, __LINE__); abort(); }
14#endif /* DEBUG_DEV */
15
16/* ******** internal API ******** */
17
18/* Return pointer to <off> relative to <buf> head. Support buffer wrapping. */
19static char *ncb_peek(const struct ncbuf *buf, ncb_sz_t off)
20{
21 char *ptr = ncb_head(buf) + off;
22 if (ptr >= buf->area + buf->size)
23 ptr -= buf->size;
24 return ptr;
25}
26
27/* Returns the reserved space of <buf> which contains the size of the first
28 * data block.
29 */
30static char *ncb_reserved(const struct ncbuf *buf)
31{
32 return ncb_peek(buf, buf->size - NCB_RESERVED_SZ);
33}
34
35/* Encode <off> at <st> position in <buf>. Support wrapping. */
36static void ncb_write_off(const struct ncbuf *buf, char *st, ncb_sz_t off)
37{
38 int i;
39
40 BUG_ON_HOT(st >= buf->area + buf->size);
41
42 for (i = 0; i < sizeof(ncb_sz_t); ++i) {
43 (*st) = off >> (8 * i) & 0xff;
44
45 if ((++st) == ncb_wrap(buf))
46 st = ncb_orig(buf);
47 }
48}
49
50/* Decode offset stored at <st> position in <buf>. Support wrapping. */
51static ncb_sz_t ncb_read_off(const struct ncbuf *buf, char *st)
52{
53 int i;
54 ncb_sz_t off = 0;
55
56 BUG_ON_HOT(st >= buf->area + buf->size);
57
58 for (i = 0; i < sizeof(ncb_sz_t); ++i) {
59 off |= (unsigned char )(*st) << (8 * i);
60
61 if ((++st) == ncb_wrap(buf))
62 st = ncb_orig(buf);
63 }
64
65 return off;
66}
67
68/* ******** public API ******** */
69
70int ncb_is_null(const struct ncbuf *buf)
71{
72 return buf->size == 0;
73}
74
75/* Initialize or reset <buf> by clearing all data. Its size is untouched.
76 * Buffer is positioned to <head> offset. Use 0 to realign it.
77 */
78void ncb_init(struct ncbuf *buf, ncb_sz_t head)
79{
80 BUG_ON_HOT(head >= buf->size);
81 buf->head = head;
82
83 ncb_write_off(buf, ncb_reserved(buf), 0);
84 ncb_write_off(buf, ncb_head(buf), ncb_size(buf));
85 ncb_write_off(buf, ncb_peek(buf, sizeof(ncb_sz_t)), 0);
86}
87
88/* Construct a ncbuf with all its parameters. */
89struct ncbuf ncb_make(char *area, ncb_sz_t size, ncb_sz_t head)
90{
91 struct ncbuf buf;
92
93 /* Ensure that there is enough space for the reserved space and data.
94 * This is the minimal value to not crash later.
95 */
96 BUG_ON_HOT(size <= NCB_RESERVED_SZ);
97
98 buf.area = area;
99 buf.size = size;
100 buf.head = head;
101
102 return buf;
103}
104
105/* Returns start of allocated buffer area. */
106char *ncb_orig(const struct ncbuf *buf)
107{
108 return buf->area;
109}
110
111/* Returns current head pointer into buffer area. */
112char *ncb_head(const struct ncbuf *buf)
113{
114 return buf->area + buf->head;
115}
116
117/* Returns the first byte after the allocated buffer area. */
118char *ncb_wrap(const struct ncbuf *buf)
119{
120 return buf->area + buf->size;
121}
122
123/* Returns the usable size of <buf> for data storage. This is the size of the
124 * allocated buffer without the reserved header space.
125 */
126ncb_sz_t ncb_size(const struct ncbuf *buf)
127{
128 return buf->size - NCB_RESERVED_SZ;
129}
130
131/* Returns true if there is no data anywhere in <buf>. */
132int ncb_is_empty(const struct ncbuf *buf)
133{
134 BUG_ON_HOT(*ncb_reserved(buf) + *ncb_head(buf) > ncb_size(buf));
135 return *ncb_reserved(buf) == 0 && *ncb_head(buf) == ncb_size(buf);
136}
137
138/* Returns true if no more data can be inserted in <buf>. */
139int ncb_is_full(const struct ncbuf *buf)
140{
141 BUG_ON_HOT(ncb_read_off(buf, ncb_reserved(buf)) > ncb_size(buf));
142 return ncb_read_off(buf, ncb_reserved(buf)) == ncb_size(buf);
143}