Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / gdp / gdp_buf.c @ master

History | View | Annotate | Download (11.7 KB)

1 a2be4838 Eric Allman
/* vim: set ai sw=4 sts=4 ts=4 :*/
2
3 22442bd4 Eric Allman
/*
4
**        GDP_BUF --- data buffers for the GDP
5 055d3009 Eric Allman
**
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 c87dd166 Eric Allman
**        Copyright (c) 2015-2019, Regents of the University of California.
11 6bd5476b Eric Allman
**        All rights reserved.
12 055d3009 Eric Allman
**
13 6bd5476b Eric Allman
**        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 055d3009 Eric Allman
**
19 6bd5476b Eric Allman
**        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 055d3009 Eric Allman
**
24 6bd5476b Eric Allman
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
25 055d3009 Eric Allman
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 6bd5476b Eric Allman
**        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 055d3009 Eric Allman
**        ----- END LICENSE BLOCK -----
31 22442bd4 Eric Allman
*/
32
33 a2be4838 Eric Allman
#include "gdp.h"
34
#include "gdp_buf.h"
35
36 276bb271 Eric Allman
#include <ep/ep_dbg.h>
37
38
#include <errno.h>
39 22442bd4 Eric Allman
#include <stdarg.h>
40 2e4a5d7d Eric Allman
#include <string.h>
41 723cc82b Eric Allman
#include <arpa/inet.h>
42 22442bd4 Eric Allman
43 276bb271 Eric Allman
static EP_DBG        Dbg = EP_DBG_INIT("gdp.buf", "GDP buffer processing");
44
45 bfecf573 Eric Allman
#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 276bb271 Eric Allman
                        } while (false)
56
57 b45c1b3c Eric Allman
/*
58
**  Create a new buffer
59
*/
60
61 22442bd4 Eric Allman
gdp_buf_t *
62
gdp_buf_new(void)
63
{
64
        return evbuffer_new();
65
}
66
67 b45c1b3c Eric Allman
/*
68
**  Reset the contents of a buffer.
69
**                Returns 0 on success, -1 on failure.
70
*/
71
72 22442bd4 Eric Allman
int
73
gdp_buf_reset(gdp_buf_t *b)
74
{
75
        return evbuffer_drain(b, evbuffer_get_length(b));
76
}
77
78 b45c1b3c Eric Allman
/*
79
**  Free a buffer.
80
*/
81
82 22442bd4 Eric Allman
void
83
gdp_buf_free(gdp_buf_t *b)
84
{
85
        evbuffer_free(b);
86
}
87
88 b45c1b3c Eric Allman
/*
89
**  Set a mutex for a buffer.
90
*/
91
92 22442bd4 Eric Allman
void
93
gdp_buf_setlock(gdp_buf_t *buf, EP_THR_MUTEX *m)
94
{
95
        evbuffer_enable_locking(buf, m);
96
}
97
98 b45c1b3c Eric Allman
/*
99 498d08e3 Eric Allman
**  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 b45c1b3c Eric Allman
**  Get the amount of data in a buffer.
116
*/
117
118 22442bd4 Eric Allman
size_t
119 0d8c13e8 Eric Allman
gdp_buf_getlength(const gdp_buf_t *buf)
120 22442bd4 Eric Allman
{
121
        return evbuffer_get_length(buf);
122
}
123
124 b45c1b3c Eric Allman
/*
125
**  Read data from buffer.
126
**                Returns number of bytes actually read.
127
*/
128
129 22442bd4 Eric Allman
size_t
130
gdp_buf_read(gdp_buf_t *buf, void *out, size_t sz)
131
{
132 276bb271 Eric Allman
        int istat = evbuffer_remove(buf, out, sz);
133
        DIAGNOSE("read", istat);
134
        return istat;
135 22442bd4 Eric Allman
}
136
137 b45c1b3c Eric Allman
/*
138 5a73c6ad Eric Allman
**  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 b45c1b3c Eric Allman
**  "Peek" at data in a buffer.
156
**                Like read, but leaves the buffer intact.
157
*/
158
159 22442bd4 Eric Allman
size_t
160
gdp_buf_peek(gdp_buf_t *buf, void *out, size_t sz)
161
{
162 76aa13ad Eric Allman
        ssize_t s = evbuffer_copyout(buf, out, sz);
163 a5d01ba1 Eric Allman
        DIAGNOSE("peek", (int) s);
164 76aa13ad Eric Allman
        if (s < 0)
165
                return 0;
166
        return s;
167 22442bd4 Eric Allman
}
168
169 b45c1b3c Eric Allman
/*
170
**  Remove data from a buffer (and discard it).
171
**                Returns 0 on success, -1 on failure.
172
*/
173
174 22442bd4 Eric Allman
int
175
gdp_buf_drain(gdp_buf_t *buf, size_t sz)
176
{
177 276bb271 Eric Allman
        int istat = evbuffer_drain(buf, sz);
178
        DIAGNOSE("drain", istat);
179
        return istat;
180 22442bd4 Eric Allman
}
181
182 b45c1b3c Eric Allman
/*
183
**  Return a pointer to the data in a buffer (kind of like peek w/o copy).
184
*/
185
186 22442bd4 Eric Allman
unsigned char *
187
gdp_buf_getptr(gdp_buf_t *buf, size_t sz)
188
{
189
        return evbuffer_pullup(buf, sz);
190
}
191
192 b45c1b3c Eric Allman
/*
193
**  Write data to a buffer.
194
**                Returns 0 on success, -1 on failure.
195
*/
196
197 22442bd4 Eric Allman
int
198 aefbbfd2 Paul Bramsen
gdp_buf_write(gdp_buf_t *buf, const void *in, size_t sz)
199 22442bd4 Eric Allman
{
200 276bb271 Eric Allman
        int istat = evbuffer_add(buf, in, sz);
201
        DIAGNOSE("write", istat);
202
        return istat;
203 22442bd4 Eric Allman
}
204
205 b45c1b3c Eric Allman
/*
206
**  Do a "printf" on to the end of a buffer.
207
**                Returns the number of bytes added.
208
*/
209
210 22442bd4 Eric Allman
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 b45c1b3c Eric Allman
/*
223
**  Append the contents of one buffer onto another.
224
**                Returns 0 on success, -1 on failure.
225 39f2b683 Eric Allman
**                This removes the data from ibuf and appends it to obuf.
226 b45c1b3c Eric Allman
*/
227
228 22442bd4 Eric Allman
int
229 328ab6a8 Eric Allman
gdp_buf_move(gdp_buf_t *obuf, gdp_buf_t *ibuf, ssize_t sz)
230 22442bd4 Eric Allman
{
231 5a73c6ad Eric Allman
        if (sz == -1)
232
                sz = gdp_buf_getlength(ibuf);
233 328ab6a8 Eric Allman
        return evbuffer_remove_buffer(ibuf, obuf, (size_t) sz);
234 22442bd4 Eric Allman
}
235
236 b45c1b3c Eric Allman
/*
237 e7b2a80c Eric Allman
**  Duplicate the contents of one buffer into another.
238
**                Does not change ibuf.
239
*/
240
241
// helper routine to minimize #ifdefs
242 5a73c6ad Eric Allman
# ifndef LIBEVENT_USE_EVBUFFER_ADD_BUFFER_REFERENCE
243
#  define LIBEVENT_USE_EVBUFFER_ADD_BUFFER_REFERENCE        0
244
# endif
245
246 e7b2a80c Eric Allman
static int
247
_gdp_buf_raw_copy(gdp_buf_t *obuf, gdp_buf_t *ibuf)
248
{
249
        int istat = -1;
250
251 5a73c6ad Eric Allman
#if LIBEVENT_VERSION_NUMBER > 0x02010100        // 2.1.1-alpha
252 dd081d69 Eric Allman
# 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 e7b2a80c Eric Allman
        istat = evbuffer_add_buffer_reference(ibuf, obuf);
257 dd081d69 Eric Allman
# else
258
        // Alternative implementation should evbuffer_add_buffer_reference not work.
259 5a73c6ad Eric Allman
        // This physically copies the data (twice --- ugh).
260 e7b2a80c Eric Allman
        int nleft = evbuffer_get_length(ibuf);
261
        struct evbuffer_ptr bufpos;
262
263
        evbuffer_ptr_set(ibuf, &bufpos, 0, EVBUFFER_PTR_SET);
264 a5d01ba1 Eric Allman
        if (nleft == 0)
265
                istat = 0;
266 e7b2a80c Eric Allman
        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 dd081d69 Eric Allman
                nleft -= n_copied;
284 e7b2a80c Eric Allman
        }
285 dd081d69 Eric Allman
# endif // LIBEVENT_USE_EVBUFFER_ADD_BUFFER_REFERENCE
286
#else // LIBEVENT_VERSION_NUMBER <= 0x02010100        (pre 2.1.1-alpha)
287 e7b2a80c Eric Allman
        // this implementation may be expensive if ibuf is large
288
        ssize_t buflen = evbuffer_get_length(ibuf);
289 7bc0e2cf Eric Allman
        if (buflen == 0)
290
                return 0;
291 e7b2a80c Eric Allman
        unsigned char *p = evbuffer_pullup(ibuf, buflen);
292
        if (p != NULL)
293
                istat = evbuffer_add(obuf, p, buflen);
294 7bc0e2cf Eric Allman
        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 e7b2a80c Eric Allman
        }
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 dd081d69 Eric Allman
gdp_buf_dup(gdp_buf_t *ibuf)
323 e7b2a80c Eric Allman
{
324
        gdp_buf_t *nbuf = gdp_buf_new();
325
        int istat;
326
327 dd081d69 Eric Allman
        istat = _gdp_buf_raw_copy(nbuf, ibuf);
328 e7b2a80c Eric Allman
        DIAGNOSE("dup", istat);
329
        return nbuf;
330
}
331
332
/*
333 b45c1b3c Eric Allman
**  Dump buffer to a file (for debugging).
334
*/
335
336 a2be4838 Eric Allman
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 2e4a5d7d Eric Allman
343 b45c1b3c Eric Allman
/*
344 af06cfb4 Eric Allman
**  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 b45c1b3c Eric Allman
**  Get a 32 bit unsigned int in network byte order from a buffer.
384
*/
385
386 2e4a5d7d Eric Allman
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 b45c1b3c Eric Allman
/*
396 af06cfb4 Eric Allman
**  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 b45c1b3c Eric Allman
**  Get a 48 bit unsigned int in network byte order from a buffer.
412
*/
413
414 2e4a5d7d Eric Allman
uint64_t
415 a0a21282 Eric Allman
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 b45c1b3c Eric Allman
/*
426 af06cfb4 Eric Allman
**  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 b45c1b3c Eric Allman
**  Get a 64 bit unsigned int in network byte order from a buffer.
451
*/
452
453 a0a21282 Eric Allman
uint64_t
454 2e4a5d7d Eric Allman
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 b45c1b3c Eric Allman
/*
474
**  Get a time stamp in network byte order from a buffer.
475
*/
476
477 2e4a5d7d Eric Allman
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 b45c1b3c Eric Allman
/*
490 af06cfb4 Eric Allman
**  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 276bb271 Eric Allman
        int istat = evbuffer_add(buf, &t, sizeof t);
498
        DIAGNOSE("put_int32", istat);
499 af06cfb4 Eric Allman
}
500
501
502
/*
503 b45c1b3c Eric Allman
**  Put a 32 bit unsigned integer to a buffer in network byte order.
504
*/
505
506 2e4a5d7d Eric Allman
void
507
gdp_buf_put_uint32(gdp_buf_t *buf, const uint32_t v)
508
{
509
        uint32_t t = htonl(v);
510 276bb271 Eric Allman
        int istat = evbuffer_add(buf, &t, sizeof t);
511
        DIAGNOSE("put_uint32", istat);
512 2e4a5d7d Eric Allman
}
513
514
515 b45c1b3c Eric Allman
/*
516 af06cfb4 Eric Allman
**  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 276bb271 Eric Allman
        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 af06cfb4 Eric Allman
}
530
531
532
/*
533 b45c1b3c Eric Allman
**  Put a 48 bit unsigned integer to a buffer in network byte order.
534
*/
535
536 2e4a5d7d Eric Allman
void
537 a0a21282 Eric Allman
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 276bb271 Eric Allman
        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 a0a21282 Eric Allman
}
547
548
549 b45c1b3c Eric Allman
/*
550 af06cfb4 Eric Allman
**  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 276bb271 Eric Allman
        int istat;
558 af06cfb4 Eric Allman
559
        if (htonl(num) == num)
560
        {
561 276bb271 Eric Allman
                istat = evbuffer_add(buf, &v, sizeof v);
562 af06cfb4 Eric Allman
        }
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 276bb271 Eric Allman
                istat = evbuffer_add(buf, &t, sizeof t);
569 af06cfb4 Eric Allman
        }
570 276bb271 Eric Allman
        DIAGNOSE("put_int64", istat);
571 af06cfb4 Eric Allman
}
572
573
574
/*
575 b45c1b3c Eric Allman
**  Put a 64 bit unsigned integer to a buffer in network byte order.
576
*/
577
578 a0a21282 Eric Allman
void
579 2e4a5d7d Eric Allman
gdp_buf_put_uint64(gdp_buf_t *buf, const uint64_t v)
580
{
581
        static const int32_t num = 42;
582 276bb271 Eric Allman
        int istat;
583 2e4a5d7d Eric Allman
584
        if (htonl(num) == num)
585
        {
586 276bb271 Eric Allman
                istat = evbuffer_add(buf, &v, sizeof v);
587 2e4a5d7d Eric Allman
        }
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 276bb271 Eric Allman
                istat = evbuffer_add(buf, &t, sizeof t);
594 2e4a5d7d Eric Allman
        }
595 276bb271 Eric Allman
        DIAGNOSE("put_uint64", istat);
596 2e4a5d7d Eric Allman
}
597
598
599 b45c1b3c Eric Allman
/*
600
**  Put a time stamp to a buffer in network byte order.
601
*/
602
603 2e4a5d7d Eric Allman
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
}