summaryrefslogtreecommitdiffstats
path: root/nhrpd/zbuf.h
blob: 73d7073447fed857ef3bbd9b4c52a78f2a0becaa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/* Stream/packet buffer API
 * Copyright (c) 2014-2015 Timo Teräs
 *
 * This file is free software: you may copy, redistribute and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 */

#ifndef ZBUF_H
#define ZBUF_H

#include <stdint.h>
#include <string.h>
#include <endian.h>
#include <sys/types.h>

#include "zassert.h"
#include "list.h"

struct zbuf {
	struct list_head queue_list;
	unsigned allocated : 1;
	unsigned error : 1;
	uint8_t *buf, *end;
	uint8_t *head, *tail;
};

struct zbuf_queue {
	struct list_head queue_head;
};

struct zbuf *zbuf_alloc(size_t size);
void zbuf_init(struct zbuf *zb, void *buf, size_t len, size_t datalen);
void zbuf_free(struct zbuf *zb);

static inline size_t zbuf_size(struct zbuf *zb)
{
	return zb->end - zb->buf;
}

static inline size_t zbuf_used(struct zbuf *zb)
{
	return zb->tail - zb->head;
}

static inline size_t zbuf_tailroom(struct zbuf *zb)
{
	return zb->end - zb->tail;
}

static inline size_t zbuf_headroom(struct zbuf *zb)
{
	return zb->head - zb->buf;
}

void zbuf_reset(struct zbuf *zb);
void zbuf_reset_head(struct zbuf *zb, void *ptr);
ssize_t zbuf_read(struct zbuf *zb, int fd, size_t maxlen);
ssize_t zbuf_write(struct zbuf *zb, int fd);
ssize_t zbuf_recv(struct zbuf *zb, int fd);
ssize_t zbuf_send(struct zbuf *zb, int fd);

static inline void zbuf_set_rerror(struct zbuf *zb)
{
	zb->error = 1;
	zb->head = zb->tail;
}

static inline void zbuf_set_werror(struct zbuf *zb)
{
	zb->error = 1;
	zb->tail = zb->end;
}

static inline void *__zbuf_pull(struct zbuf *zb, size_t size, int error)
{
	void *head = zb->head;
	if (size > zbuf_used(zb)) {
		if (error) zbuf_set_rerror(zb);
		return NULL;
	}
	zb->head += size;
	return head;
}

#define zbuf_pull(zb, type) ((type *)__zbuf_pull(zb, sizeof(type), 1))
#define zbuf_pulln(zb, sz) ((void *)__zbuf_pull(zb, sz, 1))
#define zbuf_may_pull(zb, type) ((type *)__zbuf_pull(zb, sizeof(type), 0))
#define zbuf_may_pulln(zb, sz) ((void *)__zbuf_pull(zb, sz, 0))

void *zbuf_may_pull_until(struct zbuf *zb, const char *sep, struct zbuf *msg);

static inline void zbuf_get(struct zbuf *zb, void *dst, size_t len)
{
	void *src = zbuf_pulln(zb, len);
	if (src) memcpy(dst, src, len);
}

static inline uint8_t zbuf_get8(struct zbuf *zb)
{
	uint8_t *src = zbuf_pull(zb, uint8_t);
	if (src) return *src;
	return 0;
}

static inline uint32_t zbuf_get32(struct zbuf *zb)
{
	struct unaligned32 {
		uint32_t value;
	} __attribute__((packed));

	struct unaligned32 *v = zbuf_pull(zb, struct unaligned32);
	if (v) return v->value;
	return 0;
}

static inline uint16_t zbuf_get_be16(struct zbuf *zb)
{
	struct unaligned16 {
		uint16_t value;
	} __attribute__((packed));

	struct unaligned16 *v = zbuf_pull(zb, struct unaligned16);
	if (v) return be16toh(v->value);
	return 0;
}

static inline uint32_t zbuf_get_be32(struct zbuf *zb)
{
	return be32toh(zbuf_get32(zb));
}

static inline void *__zbuf_push(struct zbuf *zb, size_t size, int error)
{
	void *tail = zb->tail;
	if (size > zbuf_tailroom(zb)) {
		if (error) zbuf_set_werror(zb);
		return NULL;
	}
	zb->tail += size;
	return tail;
}

#define zbuf_push(zb, type) ((type *)__zbuf_push(zb, sizeof(type), 1))
#define zbuf_pushn(zb, sz) ((void *)__zbuf_push(zb, sz, 1))
#define zbuf_may_push(zb, type) ((type *)__zbuf_may_push(zb, sizeof(type), 0))
#define zbuf_may_pushn(zb, sz) ((void *)__zbuf_push(zb, sz, 0))

static inline void zbuf_put(struct zbuf *zb, const void *src, size_t len)
{
	void *dst = zbuf_pushn(zb, len);
	if (dst) memcpy(dst, src, len);
}

static inline void zbuf_put8(struct zbuf *zb, uint8_t val)
{
	uint8_t *dst = zbuf_push(zb, uint8_t);
	if (dst) *dst = val;
}

static inline void zbuf_put_be16(struct zbuf *zb, uint16_t val)
{
	struct unaligned16 {
		uint16_t value;
	} __attribute__((packed));

	struct unaligned16 *v = zbuf_push(zb, struct unaligned16);
	if (v) v->value = htobe16(val);
}

static inline void zbuf_put_be32(struct zbuf *zb, uint32_t val)
{
	struct unaligned32 {
		uint32_t value;
	} __attribute__((packed));

	struct unaligned32 *v = zbuf_push(zb, struct unaligned32);
	if (v) v->value = htobe32(val);
}

void zbuf_copy(struct zbuf *zb, struct zbuf *src, size_t len);

void zbufq_init(struct zbuf_queue *);
void zbufq_reset(struct zbuf_queue *);
void zbufq_queue(struct zbuf_queue *, struct zbuf *);
int zbufq_write(struct zbuf_queue *, int);

#endif