<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.
</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/83fb13822db0eea2ee6aa21715dd33799bc0922e">https://github.com/macports/macports-legacy-support/commit/83fb13822db0eea2ee6aa21715dd33799bc0922e</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 83fb13822db0eea2ee6aa21715dd33799bc0922e
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Sat Mar 1 12:22:00 2025 -0800
<span style='display:block; white-space:pre;color:#404040;'> Add packet test (for timestamps).
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'> Detects known failures without fixes.
</span><span style='display:block; white-space:pre;color:#404040;'> Passes on all platforms with fixes.
</span>---
test/test_packet.c | 549 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 549 insertions(+)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_packet.c b/test/test_packet.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..baa97df
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_packet.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,549 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2025 Frederick H. G. Wright II <fw@fwright.net>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Test for packet-related issues, currently just timestamps.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <libgen.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stddef.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdint.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <netinet/in.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/param.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/socket.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/sysctl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <mach/mach_time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_OSVER_CLASS CTL_KERN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_OSVER_ITEM KERN_OSRELEASE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CMSG_DATALEN(cmsg) ((uint8_t *) (cmsg) + (cmsg)->cmsg_len \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ - (uint8_t *) CMSG_DATA(cmsg))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct timeval timeval_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define BILLION64 1000000000ULL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MAX_TV_USEC 1000000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MAX_TV_NSEC 1000000000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MAX_MACH_TIME (1ULL << 60) /* Arbitrary >36-year uptime limit */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TS_TYPES \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_ONE(none,,0,NULL,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_ONE(tv,struct timeval,sizeof(timeval_t),get_timeval_ts,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_ONE(u64mach,uint64_t (mach),sizeof(uint64_t),get_mach_ts,11) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TS_ONE(name,str,size,get,minver) ts_##name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef enum ts_type {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} ts_type_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef TS_ONE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TS_ONE(name,str,size,get,minver) #str,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char * const ts_type_names[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef TS_ONE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TS_ONE(name,str,size,get,minver) size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const int ts_sizes[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef TS_ONE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TS_ONE(name,str,size,get,minver) minver,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const int ts_min_darwin[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef TS_ONE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Handling for mismatched timestamp formats, copied from ntpsec
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Since this particular bug is not currently fixed here, we duplicate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the ntpsec workaround to avoid a test failure. This is just a verbatim
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copy, and handles more issues than we'll see here.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const union {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint8_t c[8];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint64_t i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} endian_test = {{1, 2, 3, 4, 5, 6, 7, 8}};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ENDIAN_LITTLE 0x0807060504030201ULL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define IS_LITTLE_ENDIAN (endian_test.i == ENDIAN_LITTLE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static struct timeval *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+access_cmsg_timeval(struct cmsghdr *cmsghdr, struct timeval *temp)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct timeval_3232 {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint32_t tv_sec; /* Unsigned to get past 2038 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int32_t tv_usec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } *tv3232p;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct timeval_6432 {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int64_t tv_sec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int32_t tv_usec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } *tv6432p;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #define SIZEOF_PACKED_TIMEVAL6432 (sizeof(int64_t) + sizeof(int32_t))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct timeval_6464 {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int64_t tv_sec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint32_t tv_usec[2]; /* Unsigned for compares */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } *tv6464p;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int datalen = CMSG_DATALEN(cmsghdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) access_cmsg_timeval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (datalen == sizeof(struct timeval)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (struct timeval *) CMSG_DATA(cmsghdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (datalen) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case sizeof(struct timeval_3232):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tv3232p = (struct timeval_3232 *) CMSG_DATA(cmsghdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_sec = tv3232p->tv_sec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_usec = tv3232p->tv_usec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case SIZEOF_PACKED_TIMEVAL6432:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tv6432p = (struct timeval_6432 *) CMSG_DATA(cmsghdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_sec = tv6432p->tv_sec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_usec = tv6432p->tv_usec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case sizeof(struct timeval_6464):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tv6464p = (struct timeval_6464 *) CMSG_DATA(cmsghdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_sec = tv6464p->tv_sec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (IS_LITTLE_ENDIAN) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_usec = tv6464p->tv_usec[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (tv6464p->tv_usec[0] == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (tv6464p->tv_usec[1] < MAX_TV_USEC) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_usec = tv6464p->tv_usec[1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_usec = tv6464p->tv_usec[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (tv6464p->tv_usec[0] < MAX_TV_USEC) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ temp->tv_usec = tv6464p->tv_usec[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* FALLTHRU to default (invalid timestamp) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ memset(temp, 0, sizeof(struct timeval));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return temp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Timestamp checks & conversions to uint64 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static uint64_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+timeval2nanos(timeval_t *tvp)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return tvp->tv_sec * BILLION64 + tvp->tv_usec * 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef uint64_t ts_func_t(struct cmsghdr *cmsghdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static uint64_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_timeval_ts(struct cmsghdr *cmsghdr)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timeval_t tvtemp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timeval_t *tvp = access_cmsg_timeval(cmsghdr, &tvtemp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((uint64_t) tvp->tv_usec >= MAX_TV_USEC) return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return timeval2nanos(tvp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static uint64_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_mach_ts(struct cmsghdr *cmsghdr)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint64_t val = *((uint64_t *) CMSG_DATA(cmsghdr));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return val >= MAX_MACH_TIME ? 0 : val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define TS_ONE(name,str,size,get,minver) get,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ts_func_t *ts_getters[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TS_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef TS_ONE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static unsigned long long
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+mach2ns(uint64_t mach_time)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static mach_timebase_info_data_t mach_scale = {0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!mach_scale.numer || !mach_scale.denom) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mach_timebase_info(&mach_scale) != KERN_SUCCESS) return mach_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (double) mach_time * mach_scale.numer / mach_scale.denom;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Data for tests */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char sample[] = "The Quick Brown Fox";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static uint8_t dbuf[256];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static uint8_t cbuf[256];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char osver[256];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static uint32_t darwinver = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_osver(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int mib[] = {SYSCTL_OSVER_CLASS, SYSCTL_OSVER_ITEM};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int miblen = sizeof(mib) / sizeof(mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size_t len = sizeof(osver);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *cp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sysctl(mib, miblen, osver, &len, NULL, 0)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (len <= 0 || len >= (ssize_t) sizeof(osver)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ osver[len] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (osver[len - 1] == '\n') osver[len - 1] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ darwinver = strtoul(osver, &cp, 10);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!darwinver || (*cp && *cp != '.')) return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct times_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timeval_t tv1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint64_t mt1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timeval_t tv2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint64_t mt2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} times_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Test one packet via loopback */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_packet(int sockopt, socklen_t *cbuflen, times_t *tp, ts_type_t tstype)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *err = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int saverr, sockin = -1, sockout = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct sockaddr_in addrin = {.sin_family = AF_INET};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct sockaddr_in addrout = {.sin_family = AF_INET};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct sockaddr_in addrinused, addroutused;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ socklen_t addrinused_len, addroutused_len;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct iovec msgiov = {.iov_base = dbuf, .iov_len = sizeof(dbuf)};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct msghdr hdr = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .msg_name = NULL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .msg_namelen = 0,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .msg_iov = &msgiov,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .msg_iovlen = 1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const int trueval = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint32_t *cbufp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ hdr.msg_control = cbuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ hdr.msg_controllen = *cbuflen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Make unpopulated buffer obvious */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cbufp = (uint32_t *) cbuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (cbufp < (uint32_t *) (cbuf + sizeof(cbuf))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *cbufp++ = 0xDEADBEEFU;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ do {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((sockin = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "socket() in";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((sockout = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "socket() out";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sockopt && setsockopt(sockin, SOL_SOCKET, sockopt,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (const void *) &trueval, sizeof(trueval)) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (errno == ENOPROTOOPT && darwinver < ts_min_darwin[tstype]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "*setsockopt()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "setsockopt()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ addrin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (bind(sockin, (struct sockaddr *) &addrin, sizeof(addrin))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "bind() in";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ addrinused_len = sizeof(addrinused);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (getsockname(sockin,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (struct sockaddr *) &addrinused, &addrinused_len)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "getsockname() in";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ addrout.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (bind(sockout, (struct sockaddr *) &addrout, sizeof(addrout))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "bind() out";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ addroutused_len = sizeof(addroutused);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (getsockname(sockout,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (struct sockaddr *) &addroutused, &addroutused_len)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "getsockname() out";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (connect(sockin, (struct sockaddr *) &addroutused, addroutused_len)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "connect() in->out";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (connect(sockout, (struct sockaddr *) &addrinused, addrinused_len)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "connect() out->in";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (gettimeofday(&tp->tv1, NULL)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "pre-send gettimeofday()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (tstype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case ts_u64mach:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(tp->mt1 = mach_absolute_time())) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "pre-send mach_absolute_time()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default: break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (err) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (send(sockout, sample, sizeof(sample), 0) != sizeof(sample)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "send()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (recvmsg(sockin, &hdr, 0) != sizeof(sample)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "recvmsg()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (tstype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case ts_u64mach:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(tp->mt2 = mach_absolute_time())) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "post-recv mach_absolute_time()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default: break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (err) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (gettimeofday(&tp->tv2, NULL)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "post-recv gettimeofday()";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *cbuflen = hdr.msg_controllen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (strncmp((const char *) dbuf, sample, sizeof(sample))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = "received data compare";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } while(0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ saverr = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sockout >= 0) (void) close(sockout);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sockin >= 0) (void) close(sockin);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = saverr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_timestamp(const char *name, ts_type_t tstype, int sockopt, int scmtype,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *tsname = ts_type_names[tstype];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *err = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ times_t times;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ unsigned long long time1n, time2n, tsval, tsvalns = 0, tslow, tshigh;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ socklen_t cbuflen, cmsglen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct cmsghdr *cmsg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int cmsglvl, cmsgtype, hdrlen, datalen, xdatalen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint32_t *datap, *xdatap;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) printf(" Testing %s:\n", name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cbuflen = sizeof(cbuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = test_packet(sockopt, &cbuflen, ×, tstype);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (*err == '*') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Allowable error on %s: %s\n", ++err, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Error on %s: %s\n", err, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ time1n = timeval2nanos(×.tv1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ time2n = timeval2nanos(×.tv2);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cbuflen < sizeof(struct cmsghdr)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsglen = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsglvl = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsgtype = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsg = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsg = (struct cmsghdr *) cbuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsglen = cmsg->cmsg_len;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsglvl = cmsg->cmsg_level;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cmsgtype = cmsg->cmsg_type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Sent at %llu.%09llu, received at %llu.%09llu, took %llu ns\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ time1n / BILLION64, time1n % BILLION64,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ time2n / BILLION64, time2n % BILLION64,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ time2n - time1n);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (tstype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case ts_u64mach:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Mach times (ns) %llu, %llu, diff = %llu\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach2ns(times.mt1), mach2ns(times.mt2),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach2ns(times.mt2 - times.mt1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default: break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cmsgtype != scmtype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Unexpected cmsg_type %d != %d\n", cmsgtype, scmtype);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!cmsglen) return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cmsg->cmsg_level != SOL_SOCKET) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Unexpected cmsg_level %d != SOL_SOCKET\n", cmsg->cmsg_level);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ datalen = CMSG_DATALEN(cmsg);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ hdrlen = cmsglen - datalen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ datap = (uint32_t *) CMSG_DATA(cmsg);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) printf(" cmsg length = %d (%d+%d), level = %d, type = %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (int) cmsglen, hdrlen, datalen, cmsglvl, cmsgtype);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ts_sizes[tstype] && datalen != ts_sizes[tstype]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %s payload length %d != expected sizeof(%s) = %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ name, datalen, tsname, ts_sizes[tstype]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (hdrlen > (int) sizeof(*cmsg)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ xdatap = (uint32_t *) (cbuf + sizeof(*cmsg));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %s header padding:\n", name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (xdatap < datap) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" (%10u)\n", *xdatap++);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %s%spayload longwords:\n", tsname, tsname[0] ? " " : "");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (datap < (uint32_t *) (cbuf + cmsglen)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %10u (0x%08X)\n", *datap, *datap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++datap;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Check for extra data assumed by simple pointer cast */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ xdatalen = ts_sizes[tstype] - datalen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (xdatalen > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ datap = (uint32_t *) ((uint8_t *) CMSG_DATA(cmsg) + datalen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ xdatap = datap + xdatalen / sizeof(uint32_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" erroneously assumed additional payload longwords:\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (datap < xdatap) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" (%10u) (0x%08X)\n", *datap, *datap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++datap;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else xdatalen = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cbuflen > cmsglen + xdatalen) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" +%d bytes of additional cmsg data\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (int) (cbuflen - cmsglen));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ts_getters[tstype]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tsval = (*ts_getters[tstype])(cmsg);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!tsval) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %s provided invalid %s\n", name, tsname);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (tstype) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case ts_tv:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tslow = time1n; tshigh = time2n; tsvalns = tsval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case ts_u64mach:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tslow = times.mt1; tshigh = times.mt2; tsvalns = mach2ns(tsval);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tslow = 0; tshigh = ~0ULL; tsvalns = tsval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (tsval < tslow || tsval > tshigh) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %s %s value %llu is not between %llu and %llu\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ name, tsname, tsval, tslow, tshigh);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose && !ret) printf(" %s value (ns) is %llu\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tsname, tsvalns);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+main(int argc, char *argv[])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int verbose = 0, err = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *name = basename(argv[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (argc > 1 && !strcmp(argv[1], "-v")) verbose = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) printf("%s starting.\n", name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (get_osver()) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Can't get OS version\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (verbose) printf("OS is Darwin %s\n", osver);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err |= test_timestamp("(no timestamp)", ts_none, 0, -1, verbose);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err |=test_timestamp("SO_TIMESTAMP", ts_tv, SO_TIMESTAMP, SCM_TIMESTAMP,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ verbose);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* macOS enhancement in 10.7+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #ifdef SO_TIMESTAMP_MONOTONIC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err |= test_timestamp("SO_TIMESTAMP_MONOTONIC", ts_u64mach,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SO_TIMESTAMP_MONOTONIC, SCM_TIMESTAMP_MONOTONIC,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ verbose);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* The following is in macOS 10.14+ kernel sources, but not user headers. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #ifdef SO_TIMESTAMP_CONTINUOUS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err |= test_timestamp("SO_TIMESTAMP_CONTINUOUS", ts_u64mach,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SO_TIMESTAMP_CONTINUOUS, SCM_TIMESTAMP_CONTINUOUS,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ verbose);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("%s %s.\n", name, err ? "failed" : "passed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>
</pre>