gdp / gdp / gdp_buf.c @ master
History | View | Annotate | Download (11.7 KB)
1 |
/* vim: set ai sw=4 sts=4 ts=4 :*/
|
---|---|
2 |
|
3 |
/*
|
4 |
** GDP_BUF --- data buffers for the GDP
|
5 |
**
|
6 |
** ----- BEGIN LICENSE BLOCK -----
|
7 |
** GDP: Global Data Plane Support Library
|
8 |
** From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
|
9 |
**
|
10 |
** Copyright (c) 2015-2019, Regents of the University of California.
|
11 |
** All rights reserved.
|
12 |
**
|
13 |
** Permission is hereby granted, without written agreement and without
|
14 |
** license or royalty fees, to use, copy, modify, and distribute this
|
15 |
** software and its documentation for any purpose, provided that the above
|
16 |
** copyright notice and the following two paragraphs appear in all copies
|
17 |
** of this software.
|
18 |
**
|
19 |
** IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
20 |
** SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
|
21 |
** PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
|
22 |
** EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23 |
**
|
24 |
** REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
25 |
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
26 |
** FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
|
27 |
** IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
|
28 |
** OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
29 |
** OR MODIFICATIONS.
|
30 |
** ----- END LICENSE BLOCK -----
|
31 |
*/
|
32 |
|
33 |
#include "gdp.h" |
34 |
#include "gdp_buf.h" |
35 |
|
36 |
#include <ep/ep_dbg.h> |
37 |
|
38 |
#include <errno.h> |
39 |
#include <stdarg.h> |
40 |
#include <string.h> |
41 |
#include <arpa/inet.h> |
42 |
|
43 |
static EP_DBG Dbg = EP_DBG_INIT("gdp.buf", "GDP buffer processing"); |
44 |
|
45 |
#define DIAGNOSE(cmd, istat) \
|
46 |
do \
|
47 |
{ \ |
48 |
if (istat < 0 && ep_dbg_test(Dbg, 9)) \ |
49 |
{ \ |
50 |
char ebuf[40]; \ |
51 |
(void) (0 == strerror_r(errno, ebuf, sizeof ebuf)); \ |
52 |
ep_dbg_printf("gdp_buf_%s: stat %d: %s\n", \
|
53 |
cmd, istat, ebuf); \ |
54 |
} \ |
55 |
} while (false) |
56 |
|
57 |
/*
|
58 |
** Create a new buffer
|
59 |
*/
|
60 |
|
61 |
gdp_buf_t * |
62 |
gdp_buf_new(void)
|
63 |
{ |
64 |
return evbuffer_new();
|
65 |
} |
66 |
|
67 |
/*
|
68 |
** Reset the contents of a buffer.
|
69 |
** Returns 0 on success, -1 on failure.
|
70 |
*/
|
71 |
|
72 |
int
|
73 |
gdp_buf_reset(gdp_buf_t *b) |
74 |
{ |
75 |
return evbuffer_drain(b, evbuffer_get_length(b));
|
76 |
} |
77 |
|
78 |
/*
|
79 |
** Free a buffer.
|
80 |
*/
|
81 |
|
82 |
void
|
83 |
gdp_buf_free(gdp_buf_t *b) |
84 |
{ |
85 |
evbuffer_free(b); |
86 |
} |
87 |
|
88 |
/*
|
89 |
** Set a mutex for a buffer.
|
90 |
*/
|
91 |
|
92 |
void
|
93 |
gdp_buf_setlock(gdp_buf_t *buf, EP_THR_MUTEX *m) |
94 |
{ |
95 |
evbuffer_enable_locking(buf, m); |
96 |
} |
97 |
|
98 |
/*
|
99 |
** Lock/unlock a buffer
|
100 |
*/
|
101 |
|
102 |
void
|
103 |
gdp_buf_lock(gdp_buf_t *buf) |
104 |
{ |
105 |
evbuffer_lock(buf); |
106 |
} |
107 |
|
108 |
void
|
109 |
gdp_buf_unlock(gdp_buf_t *buf) |
110 |
{ |
111 |
evbuffer_unlock(buf); |
112 |
} |
113 |
|
114 |
/*
|
115 |
** Get the amount of data in a buffer.
|
116 |
*/
|
117 |
|
118 |
size_t |
119 |
gdp_buf_getlength(const gdp_buf_t *buf)
|
120 |
{ |
121 |
return evbuffer_get_length(buf);
|
122 |
} |
123 |
|
124 |
/*
|
125 |
** Read data from buffer.
|
126 |
** Returns number of bytes actually read.
|
127 |
*/
|
128 |
|
129 |
size_t |
130 |
gdp_buf_read(gdp_buf_t *buf, void *out, size_t sz)
|
131 |
{ |
132 |
int istat = evbuffer_remove(buf, out, sz);
|
133 |
DIAGNOSE("read", istat);
|
134 |
return istat;
|
135 |
} |
136 |
|
137 |
/*
|
138 |
** Get a single byte from buffer.
|
139 |
** Returns EOF if no data is available.
|
140 |
*/
|
141 |
|
142 |
int
|
143 |
gdp_buf_getchar(gdp_buf_t *buf) |
144 |
{ |
145 |
uint8_t cbuf[1];
|
146 |
int istat = evbuffer_remove(buf, cbuf, 1); |
147 |
DIAGNOSE("getchar", istat);
|
148 |
if (istat <= 0) |
149 |
return EOF; |
150 |
else
|
151 |
return cbuf[0]; |
152 |
} |
153 |
|
154 |
/*
|
155 |
** "Peek" at data in a buffer.
|
156 |
** Like read, but leaves the buffer intact.
|
157 |
*/
|
158 |
|
159 |
size_t |
160 |
gdp_buf_peek(gdp_buf_t *buf, void *out, size_t sz)
|
161 |
{ |
162 |
ssize_t s = evbuffer_copyout(buf, out, sz); |
163 |
DIAGNOSE("peek", (int) s); |
164 |
if (s < 0) |
165 |
return 0; |
166 |
return s;
|
167 |
} |
168 |
|
169 |
/*
|
170 |
** Remove data from a buffer (and discard it).
|
171 |
** Returns 0 on success, -1 on failure.
|
172 |
*/
|
173 |
|
174 |
int
|
175 |
gdp_buf_drain(gdp_buf_t *buf, size_t sz) |
176 |
{ |
177 |
int istat = evbuffer_drain(buf, sz);
|
178 |
DIAGNOSE("drain", istat);
|
179 |
return istat;
|
180 |
} |
181 |
|
182 |
/*
|
183 |
** Return a pointer to the data in a buffer (kind of like peek w/o copy).
|
184 |
*/
|
185 |
|
186 |
unsigned char * |
187 |
gdp_buf_getptr(gdp_buf_t *buf, size_t sz) |
188 |
{ |
189 |
return evbuffer_pullup(buf, sz);
|
190 |
} |
191 |
|
192 |
/*
|
193 |
** Write data to a buffer.
|
194 |
** Returns 0 on success, -1 on failure.
|
195 |
*/
|
196 |
|
197 |
int
|
198 |
gdp_buf_write(gdp_buf_t *buf, const void *in, size_t sz) |
199 |
{ |
200 |
int istat = evbuffer_add(buf, in, sz);
|
201 |
DIAGNOSE("write", istat);
|
202 |
return istat;
|
203 |
} |
204 |
|
205 |
/*
|
206 |
** Do a "printf" on to the end of a buffer.
|
207 |
** Returns the number of bytes added.
|
208 |
*/
|
209 |
|
210 |
int
|
211 |
gdp_buf_printf(gdp_buf_t *buf, const char *fmt, ...) |
212 |
{ |
213 |
va_list ap; |
214 |
int res;
|
215 |
|
216 |
va_start(ap, fmt); |
217 |
res = evbuffer_add_vprintf(buf, fmt, ap); |
218 |
va_end(ap); |
219 |
return res;
|
220 |
} |
221 |
|
222 |
/*
|
223 |
** Append the contents of one buffer onto another.
|
224 |
** Returns 0 on success, -1 on failure.
|
225 |
** This removes the data from ibuf and appends it to obuf.
|
226 |
*/
|
227 |
|
228 |
int
|
229 |
gdp_buf_move(gdp_buf_t *obuf, gdp_buf_t *ibuf, ssize_t sz) |
230 |
{ |
231 |
if (sz == -1) |
232 |
sz = gdp_buf_getlength(ibuf); |
233 |
return evbuffer_remove_buffer(ibuf, obuf, (size_t) sz);
|
234 |
} |
235 |
|
236 |
/*
|
237 |
** Duplicate the contents of one buffer into another.
|
238 |
** Does not change ibuf.
|
239 |
*/
|
240 |
|
241 |
// helper routine to minimize #ifdefs
|
242 |
# ifndef LIBEVENT_USE_EVBUFFER_ADD_BUFFER_REFERENCE
|
243 |
# define LIBEVENT_USE_EVBUFFER_ADD_BUFFER_REFERENCE 0 |
244 |
# endif
|
245 |
|
246 |
static int |
247 |
_gdp_buf_raw_copy(gdp_buf_t *obuf, gdp_buf_t *ibuf) |
248 |
{ |
249 |
int istat = -1; |
250 |
|
251 |
#if LIBEVENT_VERSION_NUMBER > 0x02010100 // 2.1.1-alpha |
252 |
# if LIBEVENT_USE_EVBUFFER_ADD_BUFFER_REFERENCE
|
253 |
// efficient, but has semantic quirks: "a buffer that has already been
|
254 |
// the outbuf of one evbuffer_add_buffer_reference call cannot be the
|
255 |
// inbuf of another"
|
256 |
istat = evbuffer_add_buffer_reference(ibuf, obuf); |
257 |
# else
|
258 |
// Alternative implementation should evbuffer_add_buffer_reference not work.
|
259 |
// This physically copies the data (twice --- ugh).
|
260 |
int nleft = evbuffer_get_length(ibuf);
|
261 |
struct evbuffer_ptr bufpos;
|
262 |
|
263 |
evbuffer_ptr_set(ibuf, &bufpos, 0, EVBUFFER_PTR_SET);
|
264 |
if (nleft == 0) |
265 |
istat = 0;
|
266 |
while (nleft > 0) |
267 |
{ |
268 |
char xbuf[4096]; |
269 |
ev_ssize_t n_copied; |
270 |
|
271 |
n_copied = evbuffer_copyout_from(ibuf, &bufpos, xbuf, sizeof xbuf);
|
272 |
if (n_copied <= 0) |
273 |
{ |
274 |
istat = (int) n_copied;
|
275 |
break;
|
276 |
} |
277 |
|
278 |
istat = evbuffer_add(obuf, xbuf, n_copied); |
279 |
if (istat < 0) |
280 |
break;
|
281 |
|
282 |
evbuffer_ptr_set(ibuf, &bufpos, (size_t) istat, EVBUFFER_PTR_ADD); |
283 |
nleft -= n_copied; |
284 |
} |
285 |
# endif // LIBEVENT_USE_EVBUFFER_ADD_BUFFER_REFERENCE |
286 |
#else // LIBEVENT_VERSION_NUMBER <= 0x02010100 (pre 2.1.1-alpha) |
287 |
// this implementation may be expensive if ibuf is large
|
288 |
ssize_t buflen = evbuffer_get_length(ibuf); |
289 |
if (buflen == 0) |
290 |
return 0; |
291 |
unsigned char *p = evbuffer_pullup(ibuf, buflen); |
292 |
if (p != NULL) |
293 |
istat = evbuffer_add(obuf, p, buflen); |
294 |
else
|
295 |
{ |
296 |
ep_dbg_cprintf(Dbg, 1,
|
297 |
"_gdp_buf_raw_copy: evbuffer_pullup failed, buflen = %zd\n",
|
298 |
buflen); |
299 |
if (errno == 0) |
300 |
errno = ENOMEM; |
301 |
} |
302 |
#endif
|
303 |
|
304 |
return istat;
|
305 |
} |
306 |
|
307 |
int
|
308 |
gdp_buf_copy(gdp_buf_t *obuf, gdp_buf_t *ibuf) |
309 |
{ |
310 |
int istat;
|
311 |
|
312 |
istat = _gdp_buf_raw_copy(obuf, ibuf); |
313 |
DIAGNOSE("copy", istat);
|
314 |
return istat;
|
315 |
} |
316 |
|
317 |
/*
|
318 |
** Create a duplicate of a buffer.
|
319 |
*/
|
320 |
|
321 |
gdp_buf_t * |
322 |
gdp_buf_dup(gdp_buf_t *ibuf) |
323 |
{ |
324 |
gdp_buf_t *nbuf = gdp_buf_new(); |
325 |
int istat;
|
326 |
|
327 |
istat = _gdp_buf_raw_copy(nbuf, ibuf); |
328 |
DIAGNOSE("dup", istat);
|
329 |
return nbuf;
|
330 |
} |
331 |
|
332 |
/*
|
333 |
** Dump buffer to a file (for debugging).
|
334 |
*/
|
335 |
|
336 |
void
|
337 |
gdp_buf_dump(gdp_buf_t *buf, FILE *fp) |
338 |
{ |
339 |
fprintf(fp, "gdp_buf @ %p: len=%zu\n",
|
340 |
buf, gdp_buf_getlength(buf)); |
341 |
} |
342 |
|
343 |
/*
|
344 |
** Get a 16 bit signed int in network byte order from a buffer.
|
345 |
*/
|
346 |
|
347 |
int16_t |
348 |
gdp_buf_get_int16(gdp_buf_t *buf) |
349 |
{ |
350 |
int16_t t; |
351 |
|
352 |
evbuffer_remove(buf, &t, sizeof t);
|
353 |
return ntohl(t);
|
354 |
} |
355 |
|
356 |
/*
|
357 |
** Get a 16 bit unsigned int in network byte order from a buffer.
|
358 |
*/
|
359 |
|
360 |
uint16_t |
361 |
gdp_buf_get_uint16(gdp_buf_t *buf) |
362 |
{ |
363 |
uint16_t t; |
364 |
|
365 |
evbuffer_remove(buf, &t, sizeof t);
|
366 |
return ntohl(t);
|
367 |
} |
368 |
|
369 |
/*
|
370 |
** Get a 32 bit signed int in network byte order from a buffer.
|
371 |
*/
|
372 |
|
373 |
int32_t |
374 |
gdp_buf_get_int32(gdp_buf_t *buf) |
375 |
{ |
376 |
uint32_t t; |
377 |
|
378 |
evbuffer_remove(buf, &t, sizeof t);
|
379 |
return ntohl(t);
|
380 |
} |
381 |
|
382 |
/*
|
383 |
** Get a 32 bit unsigned int in network byte order from a buffer.
|
384 |
*/
|
385 |
|
386 |
uint32_t |
387 |
gdp_buf_get_uint32(gdp_buf_t *buf) |
388 |
{ |
389 |
uint32_t t; |
390 |
|
391 |
evbuffer_remove(buf, &t, sizeof t);
|
392 |
return ntohl(t);
|
393 |
} |
394 |
|
395 |
/*
|
396 |
** Get a 48 bit signed int in network byte order from a buffer.
|
397 |
*/
|
398 |
|
399 |
int64_t |
400 |
gdp_buf_get_int48(gdp_buf_t *buf) |
401 |
{ |
402 |
int16_t h; |
403 |
uint32_t l; |
404 |
|
405 |
evbuffer_remove(buf, &h, sizeof h);
|
406 |
evbuffer_remove(buf, &l, sizeof l);
|
407 |
return ((int64_t) ntohs(h) << 32) | ((uint64_t) ntohl(l)); |
408 |
} |
409 |
|
410 |
/*
|
411 |
** Get a 48 bit unsigned int in network byte order from a buffer.
|
412 |
*/
|
413 |
|
414 |
uint64_t |
415 |
gdp_buf_get_uint48(gdp_buf_t *buf) |
416 |
{ |
417 |
uint16_t h; |
418 |
uint32_t l; |
419 |
|
420 |
evbuffer_remove(buf, &h, sizeof h);
|
421 |
evbuffer_remove(buf, &l, sizeof l);
|
422 |
return ((uint64_t) ntohs(h) << 32) | ((uint64_t) ntohl(l)); |
423 |
} |
424 |
|
425 |
/*
|
426 |
** Get a 64 bit signed int in network byte order from a buffer.
|
427 |
*/
|
428 |
|
429 |
int64_t |
430 |
gdp_buf_get_int64(gdp_buf_t *buf) |
431 |
{ |
432 |
int64_t t; |
433 |
static const int32_t num = 42; |
434 |
|
435 |
evbuffer_remove(buf, &t, sizeof t);
|
436 |
if (ntohl(num) == num)
|
437 |
{ |
438 |
return t;
|
439 |
} |
440 |
else
|
441 |
{ |
442 |
int32_t h = htonl((int32_t) (t >> 32));
|
443 |
uint32_t l = htonl((uint32_t) (t & UINT64_C(0xffffffff)));
|
444 |
|
445 |
return ((int64_t) l) << 32 | h; |
446 |
} |
447 |
} |
448 |
|
449 |
/*
|
450 |
** Get a 64 bit unsigned int in network byte order from a buffer.
|
451 |
*/
|
452 |
|
453 |
uint64_t |
454 |
gdp_buf_get_uint64(gdp_buf_t *buf) |
455 |
{ |
456 |
uint64_t t; |
457 |
static const int32_t num = 42; |
458 |
|
459 |
evbuffer_remove(buf, &t, sizeof t);
|
460 |
if (ntohl(num) == num)
|
461 |
{ |
462 |
return t;
|
463 |
} |
464 |
else
|
465 |
{ |
466 |
uint32_t h = htonl((uint32_t) (t >> 32));
|
467 |
uint32_t l = htonl((uint32_t) (t & UINT64_C(0xffffffff)));
|
468 |
|
469 |
return ((uint64_t) l) << 32 | h; |
470 |
} |
471 |
} |
472 |
|
473 |
/*
|
474 |
** Get a time stamp in network byte order from a buffer.
|
475 |
*/
|
476 |
|
477 |
void
|
478 |
gdp_buf_get_timespec(gdp_buf_t *buf, EP_TIME_SPEC *ts) |
479 |
{ |
480 |
uint32_t t; |
481 |
|
482 |
ts->tv_sec = gdp_buf_get_uint64(buf); |
483 |
ts->tv_nsec = gdp_buf_get_uint32(buf); |
484 |
t = gdp_buf_get_uint32(buf); |
485 |
memcpy(&ts->tv_accuracy, &t, sizeof ts->tv_accuracy);
|
486 |
} |
487 |
|
488 |
|
489 |
/*
|
490 |
** Put a 32 bit signed integer to a buffer in network byte order.
|
491 |
*/
|
492 |
|
493 |
void
|
494 |
gdp_buf_put_int32(gdp_buf_t *buf, const int32_t v)
|
495 |
{ |
496 |
int32_t t = htonl(v); |
497 |
int istat = evbuffer_add(buf, &t, sizeof t); |
498 |
DIAGNOSE("put_int32", istat);
|
499 |
} |
500 |
|
501 |
|
502 |
/*
|
503 |
** Put a 32 bit unsigned integer to a buffer in network byte order.
|
504 |
*/
|
505 |
|
506 |
void
|
507 |
gdp_buf_put_uint32(gdp_buf_t *buf, const uint32_t v)
|
508 |
{ |
509 |
uint32_t t = htonl(v); |
510 |
int istat = evbuffer_add(buf, &t, sizeof t); |
511 |
DIAGNOSE("put_uint32", istat);
|
512 |
} |
513 |
|
514 |
|
515 |
/*
|
516 |
** Put a 48 bit signed integer to a buffer in network byte order.
|
517 |
*/
|
518 |
|
519 |
void
|
520 |
gdp_buf_put_int48(gdp_buf_t *buf, const int64_t v)
|
521 |
{ |
522 |
uint16_t h = htons((v >> 32) & 0xffff); |
523 |
uint32_t l = htonl((uint32_t) (v & UINT64_C(0xffffffff)));
|
524 |
int istat;
|
525 |
istat = evbuffer_add(buf, &h, sizeof h);
|
526 |
DIAGNOSE("put_int48", istat);
|
527 |
istat = evbuffer_add(buf, &l, sizeof l);
|
528 |
DIAGNOSE("put_int48", istat);
|
529 |
} |
530 |
|
531 |
|
532 |
/*
|
533 |
** Put a 48 bit unsigned integer to a buffer in network byte order.
|
534 |
*/
|
535 |
|
536 |
void
|
537 |
gdp_buf_put_uint48(gdp_buf_t *buf, const uint64_t v)
|
538 |
{ |
539 |
uint16_t h = htons((v >> 32) & 0xffff); |
540 |
uint32_t l = htonl((uint32_t) (v & UINT64_C(0xffffffff)));
|
541 |
int istat;
|
542 |
istat = evbuffer_add(buf, &h, sizeof h);
|
543 |
DIAGNOSE("put_uint48", istat);
|
544 |
istat = evbuffer_add(buf, &l, sizeof l);
|
545 |
DIAGNOSE("put_uint48", istat);
|
546 |
} |
547 |
|
548 |
|
549 |
/*
|
550 |
** Put a 64 bit signed integer to a buffer in network byte order.
|
551 |
*/
|
552 |
|
553 |
void
|
554 |
gdp_buf_put_int64(gdp_buf_t *buf, const int64_t v)
|
555 |
{ |
556 |
static const int32_t num = 42; |
557 |
int istat;
|
558 |
|
559 |
if (htonl(num) == num)
|
560 |
{ |
561 |
istat = evbuffer_add(buf, &v, sizeof v);
|
562 |
} |
563 |
else
|
564 |
{ |
565 |
int64_t t = htonl(v & INT64_C(0xffffffff));
|
566 |
t <<= 32;
|
567 |
t |= (int64_t) htonl((int32_t) ((v >> 32)) & INT64_C(0xffffffff)); |
568 |
istat = evbuffer_add(buf, &t, sizeof t);
|
569 |
} |
570 |
DIAGNOSE("put_int64", istat);
|
571 |
} |
572 |
|
573 |
|
574 |
/*
|
575 |
** Put a 64 bit unsigned integer to a buffer in network byte order.
|
576 |
*/
|
577 |
|
578 |
void
|
579 |
gdp_buf_put_uint64(gdp_buf_t *buf, const uint64_t v)
|
580 |
{ |
581 |
static const int32_t num = 42; |
582 |
int istat;
|
583 |
|
584 |
if (htonl(num) == num)
|
585 |
{ |
586 |
istat = evbuffer_add(buf, &v, sizeof v);
|
587 |
} |
588 |
else
|
589 |
{ |
590 |
uint64_t t = htonl(((uint32_t) v & UINT64_C(0xffffffff)));
|
591 |
t <<= 32;
|
592 |
t |= (uint64_t) htonl((uint32_t) (v >> 32));
|
593 |
istat = evbuffer_add(buf, &t, sizeof t);
|
594 |
} |
595 |
DIAGNOSE("put_uint64", istat);
|
596 |
} |
597 |
|
598 |
|
599 |
/*
|
600 |
** Put a time stamp to a buffer in network byte order.
|
601 |
*/
|
602 |
|
603 |
void
|
604 |
gdp_buf_put_timespec(gdp_buf_t *buf, EP_TIME_SPEC *ts) |
605 |
{ |
606 |
gdp_buf_put_uint64(buf, ts->tv_sec); |
607 |
gdp_buf_put_uint32(buf, ts->tv_nsec); |
608 |
gdp_buf_put_uint32(buf, *((uint32_t *) &ts->tv_accuracy)); |
609 |
} |