lua/uloop: use uloop_timeout_remaining64
[project/libubox.git] / blob.c
1 /*
2 * blob - library for generating/parsing tagged binary data
3 *
4 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "blob.h"
20
21 static bool
22 blob_buffer_grow(struct blob_buf *buf, int minlen)
23 {
24 struct blob_buf *new;
25 int delta = ((minlen / 256) + 1) * 256;
26 new = realloc(buf->buf, buf->buflen + delta);
27 if (new) {
28 buf->buf = new;
29 memset(buf->buf + buf->buflen, 0, delta);
30 buf->buflen += delta;
31 }
32 return !!new;
33 }
34
35 static void
36 blob_init(struct blob_attr *attr, int id, unsigned int len)
37 {
38 len &= BLOB_ATTR_LEN_MASK;
39 len |= (id << BLOB_ATTR_ID_SHIFT) & BLOB_ATTR_ID_MASK;
40 attr->id_len = cpu_to_be32(len);
41 }
42
43 static inline struct blob_attr *
44 offset_to_attr(struct blob_buf *buf, int offset)
45 {
46 void *ptr = (char *)buf->buf + offset - BLOB_COOKIE;
47 return ptr;
48 }
49
50 static inline int
51 attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
52 {
53 return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
54 }
55
56 bool
57 blob_buf_grow(struct blob_buf *buf, int required)
58 {
59 int offset_head = attr_to_offset(buf, buf->head);
60
61 if ((buf->buflen + required) > BLOB_ATTR_LEN_MASK)
62 return false;
63 if (!buf->grow || !buf->grow(buf, required))
64 return false;
65
66 buf->head = offset_to_attr(buf, offset_head);
67 return true;
68 }
69
70 static struct blob_attr *
71 blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload)
72 {
73 int offset = attr_to_offset(buf, pos);
74 int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen;
75 struct blob_attr *attr;
76
77 if (required > 0) {
78 if (!blob_buf_grow(buf, required))
79 return NULL;
80 attr = offset_to_attr(buf, offset);
81 } else {
82 attr = pos;
83 }
84
85 blob_init(attr, id, payload + sizeof(struct blob_attr));
86 blob_fill_pad(attr);
87 return attr;
88 }
89
90 int
91 blob_buf_init(struct blob_buf *buf, int id)
92 {
93 if (!buf->grow)
94 buf->grow = blob_buffer_grow;
95
96 buf->head = buf->buf;
97 if (blob_add(buf, buf->buf, id, 0) == NULL)
98 return -ENOMEM;
99
100 return 0;
101 }
102
103 void
104 blob_buf_free(struct blob_buf *buf)
105 {
106 free(buf->buf);
107 buf->buf = NULL;
108 buf->buflen = 0;
109 }
110
111 void
112 blob_fill_pad(struct blob_attr *attr)
113 {
114 char *buf = (char *) attr;
115 int len = blob_pad_len(attr);
116 int delta = len - blob_raw_len(attr);
117
118 if (delta > 0)
119 memset(buf + len - delta, 0, delta);
120 }
121
122 void
123 blob_set_raw_len(struct blob_attr *attr, unsigned int len)
124 {
125 len &= BLOB_ATTR_LEN_MASK;
126 attr->id_len &= ~cpu_to_be32(BLOB_ATTR_LEN_MASK);
127 attr->id_len |= cpu_to_be32(len);
128 }
129
130 struct blob_attr *
131 blob_new(struct blob_buf *buf, int id, int payload)
132 {
133 struct blob_attr *attr;
134
135 attr = blob_add(buf, blob_next(buf->head), id, payload);
136 if (!attr)
137 return NULL;
138
139 blob_set_raw_len(buf->head, blob_pad_len(buf->head) + blob_pad_len(attr));
140 return attr;
141 }
142
143 struct blob_attr *
144 blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)
145 {
146 struct blob_attr *attr;
147
148 if (len < sizeof(struct blob_attr) || !ptr)
149 return NULL;
150
151 attr = blob_add(buf, blob_next(buf->head), 0, len - sizeof(struct blob_attr));
152 if (!attr)
153 return NULL;
154 blob_set_raw_len(buf->head, blob_pad_len(buf->head) + len);
155 memcpy(attr, ptr, len);
156 return attr;
157 }
158
159 struct blob_attr *
160 blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)
161 {
162 struct blob_attr *attr;
163
164 attr = blob_new(buf, id, len);
165 if (!attr)
166 return NULL;
167
168 if (ptr)
169 memcpy(blob_data(attr), ptr, len);
170 return attr;
171 }
172
173 void *
174 blob_nest_start(struct blob_buf *buf, int id)
175 {
176 unsigned long offset = attr_to_offset(buf, buf->head);
177 buf->head = blob_new(buf, id, 0);
178 if (!buf->head)
179 return NULL;
180 return (void *) offset;
181 }
182
183 void
184 blob_nest_end(struct blob_buf *buf, void *cookie)
185 {
186 struct blob_attr *attr = offset_to_attr(buf, (unsigned long) cookie);
187 blob_set_raw_len(attr, blob_pad_len(attr) + blob_len(buf->head));
188 buf->head = attr;
189 }
190
191 static const size_t blob_type_minlen[BLOB_ATTR_LAST] = {
192 [BLOB_ATTR_STRING] = 1,
193 [BLOB_ATTR_INT8] = sizeof(uint8_t),
194 [BLOB_ATTR_INT16] = sizeof(uint16_t),
195 [BLOB_ATTR_INT32] = sizeof(uint32_t),
196 [BLOB_ATTR_INT64] = sizeof(uint64_t),
197 [BLOB_ATTR_DOUBLE] = sizeof(double),
198 };
199
200 bool
201 blob_check_type(const void *ptr, unsigned int len, int type)
202 {
203 const char *data = ptr;
204
205 if (type >= BLOB_ATTR_LAST)
206 return false;
207
208 if (type >= BLOB_ATTR_INT8 && type <= BLOB_ATTR_INT64) {
209 if (len != blob_type_minlen[type])
210 return false;
211 } else {
212 if (len < blob_type_minlen[type])
213 return false;
214 }
215
216 if (type == BLOB_ATTR_STRING && data[len - 1] != 0)
217 return false;
218
219 return true;
220 }
221
222 static int
223 blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
224 {
225 int id;
226 size_t len;
227 int found = 0;
228 size_t data_len;
229
230 if (!attr || attr_len < sizeof(struct blob_attr))
231 return 0;
232
233 id = blob_id(attr);
234 if (id >= max)
235 return 0;
236
237 len = blob_raw_len(attr);
238 if (len > attr_len || len < sizeof(struct blob_attr))
239 return 0;
240
241 data_len = blob_len(attr);
242 if (data_len > len)
243 return 0;
244
245 if (info) {
246 int type = info[id].type;
247
248 if (type < BLOB_ATTR_LAST) {
249 if (!blob_check_type(blob_data(attr), data_len, type))
250 return 0;
251 }
252
253 if (info[id].minlen && len < info[id].minlen)
254 return 0;
255
256 if (info[id].maxlen && len > info[id].maxlen)
257 return 0;
258
259 if (info[id].validate && !info[id].validate(&info[id], attr))
260 return 0;
261 }
262
263 if (!data[id])
264 found++;
265
266 data[id] = attr;
267 return found;
268 }
269
270 int
271 blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
272 {
273 struct blob_attr *pos;
274 size_t len = 0;
275 int found = 0;
276 size_t rem;
277
278 if (!attr || attr_len < sizeof(struct blob_attr))
279 return 0;
280
281 len = blob_raw_len(attr);
282 if (attr_len < len)
283 return 0;
284
285 memset(data, 0, sizeof(struct blob_attr *) * max);
286 blob_for_each_attr_len(pos, attr, len, rem) {
287 found += blob_parse_attr(pos, rem, data, info, max);
288 }
289
290 return found;
291 }
292
293 /* use only on trusted input, otherwise consider blob_parse_untrusted */
294 int
295 blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
296 {
297 struct blob_attr *pos;
298 int found = 0;
299 size_t rem;
300
301 memset(data, 0, sizeof(struct blob_attr *) * max);
302 blob_for_each_attr(pos, attr, rem) {
303 found += blob_parse_attr(pos, rem, data, info, max);
304 }
305
306 return found;
307 }
308
309 bool
310 blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2)
311 {
312 if (!a1 && !a2)
313 return true;
314
315 if (!a1 || !a2)
316 return false;
317
318 if (blob_pad_len(a1) != blob_pad_len(a2))
319 return false;
320
321 return !memcmp(a1, a2, blob_pad_len(a1));
322 }
323
324 struct blob_attr *
325 blob_memdup(struct blob_attr *attr)
326 {
327 struct blob_attr *ret;
328 int size = blob_pad_len(attr);
329
330 ret = malloc(size);
331 if (!ret)
332 return NULL;
333
334 memcpy(ret, attr, size);
335 return ret;
336 }