Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

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
}