summaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/CMakeLists.txt28
-rw-r--r--src/shared/crc32.c238
-rw-r--r--src/shared/crc32.h9
-rw-r--r--src/shared/fdsignal.c4
-rw-r--r--src/shared/fdsignal.h57
-rw-r--r--src/shared/log.c36
-rw-r--r--src/shared/log.h65
-rw-r--r--src/shared/protocol.h159
-rw-r--r--src/shared/serialize.c99
-rw-r--r--src/shared/sockhelper.c42
-rw-r--r--src/shared/sockhelper.h120
-rw-r--r--src/shared/timing.c2
-rw-r--r--src/shared/timing.h162
13 files changed, 362 insertions, 659 deletions
diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt
new file mode 100644
index 0000000..a1bd49a
--- /dev/null
+++ b/src/shared/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+project(dnbd3-shared
+ LANGUAGES C)
+
+# find atomic library required by dnbd3-shared
+find_package(Stdatomic REQUIRED)
+find_package(Libatomic REQUIRED)
+
+# add compile option to get POLLRDHUP support for signals
+add_definitions(-D_GNU_SOURCE)
+
+set(DNBD3_SHARED_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/crc32.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fdsignal.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/log.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/serialize.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/sockhelper.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/timing.c)
+set(DNBD3_SHARED_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/fdsignal.inc/eventfd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fdsignal.inc/pipe64.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fdsignal.inc/pipe_malloc.c)
+
+add_library(dnbd3-shared STATIC ${DNBD3_SHARED_SOURCE_FILES})
+target_include_directories(dnbd3-shared PUBLIC ${PROJECT_INCLUDE_DIR})
+
+add_linter(dnbd3-shared-lint "${DNBD3_SHARED_SOURCE_FILES}" "${DNBD3_SHARED_HEADER_FILES}")
+add_linter_fix(dnbd3-shared-lint-fix "${DNBD3_SHARED_SOURCE_FILES}" "${DNBD3_SHARED_HEADER_FILES}")
diff --git a/src/shared/crc32.c b/src/shared/crc32.c
index db941d3..6cf9a18 100644
--- a/src/shared/crc32.c
+++ b/src/shared/crc32.c
@@ -38,24 +38,23 @@
*/
-#include "../types.h"
+#include <dnbd3/types.h>
#include <stddef.h>
-#define FAR
+#if defined(__x86_64__) || defined(__amd64__)
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include <wmmintrin.h>
+#include <stdatomic.h>
+#define zalign(n) __attribute__((aligned(n)))
+#endif
+
#define OF(args) args
-#define local static
/* Definitions for doing the crc four data bytes at a time. */
-#if !defined(NOBYFOUR)
-# define BYFOUR
-#endif
-#ifdef BYFOUR
-# define TBLS 8
-#else
-# define TBLS 1
-#endif /* BYFOUR */
+#define TBLS 8
-local const uint32_t crc_table[TBLS][256] =
+static const uint32_t crc_table[TBLS][256] =
{
{
0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
@@ -110,7 +109,6 @@ local const uint32_t crc_table[TBLS][256] =
0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
0x2d02ef8dU
-#ifdef BYFOUR
},
{
0x00000000U, 0x191b3141U, 0x32366282U, 0x2b2d53c3U, 0x646cc504U,
@@ -489,38 +487,159 @@ local const uint32_t crc_table[TBLS][256] =
0x95e6b8b1U, 0x7b490da3U, 0x1e2eb11bU, 0x483ed243U, 0x2d596efbU,
0xc3f6dbe9U, 0xa6916751U, 0x1fa9b0ccU, 0x7ace0c74U, 0x9461b966U,
0xf10605deU
-#endif
}
};
-#ifdef NO_ENDIAN
-// Currently not in use, always use the BYFOUR method with known endianness
-/* ========================================================================= */
-#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
-#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+#define PCLMUL_MIN_LEN 64
+#define PCLMUL_ALIGN 16
+#define PCLMUL_ALIGN_MASK 15
-/* ========================================================================= */
-uint32_t crc32(crc, buf, len)
- uint32_t crc;
- const uint8_t *buf;
- size_t len;
+#if defined(__x86_64__) || defined(__amd64__)
+/* crc32_simd.c
+ *
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the Chromium source repository LICENSE file.
+ *
+ * crc32_sse42_simd_(): compute the crc32 of the buffer, where the buffer
+ * length must be at least 64, and a multiple of 16. Based on:
+ *
+ * "Fast CRC Computation for Generic Polynomials Using PCLMULQDQ Instruction"
+ * V. Gopal, E. Ozturk, et al., 2009, http://intel.ly/2ySEwL0
+ */
+static uint32_t
+__attribute__((target("pclmul,sse4.1")))
+crc32pclmul(uint32_t crc, const uint8_t *buf, size_t len)
{
- if (buf == NULL) return 0;
+ /*
+ * Definitions of the bit-reflected domain constants k1,k2,k3, etc and
+ * the CRC32+Barrett polynomials given at the end of the paper.
+ */
+ static const uint64_t zalign(16) k1k2[] = { 0x0154442bd4, 0x01c6e41596 };
+ static const uint64_t zalign(16) k3k4[] = { 0x01751997d0, 0x00ccaa009e };
+ static const uint64_t zalign(16) k5k0[] = { 0x0163cd6124, 0x0000000000 };
+ static const uint64_t zalign(16) poly[] = { 0x01db710641, 0x01f7011641 };
+
+ __m128i x0, x1, x2, x3, x4, x5, x6, x7, x8, y5, y6, y7, y8;
+
+ /*
+ * There's at least one block of 64.
+ */
+ x1 = _mm_loadu_si128((__m128i *)(buf + 0x00));
+ x2 = _mm_loadu_si128((__m128i *)(buf + 0x10));
+ x3 = _mm_loadu_si128((__m128i *)(buf + 0x20));
+ x4 = _mm_loadu_si128((__m128i *)(buf + 0x30));
+
+ x1 = _mm_xor_si128(x1, _mm_cvtsi32_si128(crc));
+
+ x0 = _mm_load_si128((__m128i *)k1k2);
+
+ buf += 64;
+ len -= 64;
- crc = crc ^ 0xffffffffU;
- while (len >= 8) {
- DO8;
- len -= 8;
+ /*
+ * Parallel fold blocks of 64, if any.
+ */
+ while (len >= 64)
+ {
+ x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
+ x6 = _mm_clmulepi64_si128(x2, x0, 0x00);
+ x7 = _mm_clmulepi64_si128(x3, x0, 0x00);
+ x8 = _mm_clmulepi64_si128(x4, x0, 0x00);
+
+ x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
+ x2 = _mm_clmulepi64_si128(x2, x0, 0x11);
+ x3 = _mm_clmulepi64_si128(x3, x0, 0x11);
+ x4 = _mm_clmulepi64_si128(x4, x0, 0x11);
+
+ y5 = _mm_loadu_si128((__m128i *)(buf + 0x00));
+ y6 = _mm_loadu_si128((__m128i *)(buf + 0x10));
+ y7 = _mm_loadu_si128((__m128i *)(buf + 0x20));
+ y8 = _mm_loadu_si128((__m128i *)(buf + 0x30));
+
+ x1 = _mm_xor_si128(x1, x5);
+ x2 = _mm_xor_si128(x2, x6);
+ x3 = _mm_xor_si128(x3, x7);
+ x4 = _mm_xor_si128(x4, x8);
+
+ x1 = _mm_xor_si128(x1, y5);
+ x2 = _mm_xor_si128(x2, y6);
+ x3 = _mm_xor_si128(x3, y7);
+ x4 = _mm_xor_si128(x4, y8);
+
+ buf += 64;
+ len -= 64;
}
- if (len) do {
- DO1;
- } while (--len);
- return crc ^ 0xffffffffU;
+
+ /*
+ * Fold into 128-bits.
+ */
+ x0 = _mm_load_si128((__m128i *)k3k4);
+
+ x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
+ x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
+ x1 = _mm_xor_si128(x1, x2);
+ x1 = _mm_xor_si128(x1, x5);
+
+ x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
+ x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
+ x1 = _mm_xor_si128(x1, x3);
+ x1 = _mm_xor_si128(x1, x5);
+
+ x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
+ x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
+ x1 = _mm_xor_si128(x1, x4);
+ x1 = _mm_xor_si128(x1, x5);
+
+ /*
+ * Single fold blocks of 16, if any.
+ */
+ while (len >= 16)
+ {
+ x2 = _mm_loadu_si128((__m128i *)buf);
+
+ x5 = _mm_clmulepi64_si128(x1, x0, 0x00);
+ x1 = _mm_clmulepi64_si128(x1, x0, 0x11);
+ x1 = _mm_xor_si128(x1, x2);
+ x1 = _mm_xor_si128(x1, x5);
+
+ buf += 16;
+ len -= 16;
+ }
+
+ /*
+ * Fold 128-bits to 64-bits.
+ */
+ x2 = _mm_clmulepi64_si128(x1, x0, 0x10);
+ x3 = _mm_setr_epi32(~0, 0, ~0, 0);
+ x1 = _mm_srli_si128(x1, 8);
+ x1 = _mm_xor_si128(x1, x2);
+
+ x0 = _mm_loadl_epi64((__m128i*)k5k0);
+
+ x2 = _mm_srli_si128(x1, 4);
+ x1 = _mm_and_si128(x1, x3);
+ x1 = _mm_clmulepi64_si128(x1, x0, 0x00);
+ x1 = _mm_xor_si128(x1, x2);
+
+ /*
+ * Barret reduce to 32-bits.
+ */
+ x0 = _mm_load_si128((__m128i*)poly);
+
+ x2 = _mm_and_si128(x1, x3);
+ x2 = _mm_clmulepi64_si128(x2, x0, 0x10);
+ x2 = _mm_and_si128(x2, x3);
+ x2 = _mm_clmulepi64_si128(x2, x0, 0x00);
+ x1 = _mm_xor_si128(x1, x2);
+
+ /*
+ * Return the crc32.
+ */
+ return _mm_extract_epi32(x1, 1);
}
#endif
-#ifdef BYFOUR
-
/*
This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit
integer pointer type. This violates the strict aliasing rule, where a
@@ -533,7 +652,7 @@ uint32_t crc32(crc, buf, len)
writes to the buffer that is passed to these routines.
*/
-#ifdef LITTLE_ENDIAN
+#ifdef DNBD3_LITTLE_ENDIAN
/* ========================================================================= */
#define DOLIT4 c ^= *buf4++; \
c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
@@ -547,25 +666,36 @@ uint32_t crc32(crc, buf, len)
size_t len;
{
if (buf == NULL) return 0;
- register uint32_t c;
- register const uint32_t FAR *buf4;
+ uint32_t c;
c = ~crc;
- while (len && ((uintptr_t)buf & 3)) {
+ while (len && ((uintptr_t)buf & PCLMUL_ALIGN_MASK)) {
c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
len--;
}
-
- buf4 = (const uint32_t FAR *)(const void FAR *)buf;
- while (len >= 32) {
- DOLIT32;
- len -= 32;
- }
- while (len >= 4) {
- DOLIT4;
- len -= 4;
+#if defined(__x86_64__) || defined(__amd64__)
+ static atomic_int pclmul = -1;
+ if (pclmul == -1) {
+ pclmul = __builtin_cpu_supports("pclmul") && __builtin_cpu_supports("sse4.1");
}
- buf = (const uint8_t FAR *)buf4;
+ if (pclmul && len >= PCLMUL_MIN_LEN) {
+ c = crc32pclmul(c, buf, len & ~PCLMUL_ALIGN_MASK);
+ buf += len & ~PCLMUL_ALIGN_MASK;
+ len &= PCLMUL_ALIGN_MASK;
+ } else
+#endif
+ do {
+ const uint32_t *buf4 = (const uint32_t *)(const void *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const uint8_t *)buf4;
+ } while (0);
if (len) do {
c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
@@ -575,7 +705,7 @@ uint32_t crc32(crc, buf, len)
}
#endif
-#ifdef BIG_ENDIAN
+#ifdef DNBD3_BIG_ENDIAN
/* ========================================================================= */
#define DOBIG4 c ^= *buf4++; \
c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
@@ -590,7 +720,7 @@ uint32_t crc32(crc, buf, len)
{
if (buf == NULL) return 0;
register uint32_t c;
- register const uint32_t FAR *buf4;
+ register const uint32_t *buf4;
c = ~net_order_32(crc);
while (len && ((uintptr_t)buf & 3)) {
@@ -598,7 +728,7 @@ uint32_t crc32(crc, buf, len)
len--;
}
- buf4 = (const uint32_t FAR *)(const void FAR *)buf;
+ buf4 = (const uint32_t *)(const void *)buf;
while (len >= 32) {
DOBIG32;
len -= 32;
@@ -607,7 +737,7 @@ uint32_t crc32(crc, buf, len)
DOBIG4;
len -= 4;
}
- buf = (const uint8_t FAR *)buf4;
+ buf = (const uint8_t *)buf4;
if (len) do {
c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
@@ -617,5 +747,3 @@ uint32_t crc32(crc, buf, len)
}
#endif
-#endif /* BYFOUR */
-
diff --git a/src/shared/crc32.h b/src/shared/crc32.h
deleted file mode 100644
index 00b8bdd..0000000
--- a/src/shared/crc32.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _CRC32_H_
-#define _CRC32_H_
-
-#include <stdint.h>
-
-uint32_t crc32(uint32_t crc, const uint8_t *buf, size_t len);
-
-#endif
-
diff --git a/src/shared/fdsignal.c b/src/shared/fdsignal.c
index 5e5cf7f..1db59bd 100644
--- a/src/shared/fdsignal.c
+++ b/src/shared/fdsignal.c
@@ -1,6 +1,6 @@
-#include "fdsignal.h"
+#include <dnbd3/shared/fdsignal.h>
-#if defined(linux) || defined(__linux) || defined(__linux__)
+#if defined(__linux__)
//#warning "Using eventfd based signalling"
#include "fdsignal.inc/eventfd.c"
#elif __SIZEOF_INT__ == 4 && __SIZEOF_POINTER__ == 8
diff --git a/src/shared/fdsignal.h b/src/shared/fdsignal.h
deleted file mode 100644
index 960a2a9..0000000
--- a/src/shared/fdsignal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef _FD_SIGNAL_H_
-#define _FD_SIGNAL_H_
-
-#define SIGNAL_OK (0)
-#define SIGNAL_TIMEOUT (-2)
-#define SIGNAL_ERROR (-1)
-
-typedef struct _dnbd3_signal dnbd3_signal_t;
-
-/**
- * Create a new signal, nonblocking.
- * @return NULL on error, pointer to dnbd3_signal_t on success.
- */
-dnbd3_signal_t* signal_new();
-
-/**
- * Create a new signal, blocking.
- * @return NULL on error, pointer to dnbd3_signal_t on success.
- */
-dnbd3_signal_t* signal_newBlocking();
-
-/**
- * Trigger the given signal, so a wait or clear call will succeed.
- * @return SIGNAL_OK on success, SIGNAL_ERROR on error
- */
-int signal_call(const dnbd3_signal_t* const signal);
-
-/**
- * Wait for given signal, with an optional timeout.
- * If timeout == 0, just poll once.
- * If timeout < 0, wait forever.
- * @return > 0 telling how many times the signal was called,
- * SIGNAL_TIMEOUT if the timeout was reached,
- * SIGNAL_ERROR if some error occured
- */
-int signal_wait(const dnbd3_signal_t* const signal, int timeoutMs);
-
-/**
- * Clears any pending signals on this signal.
- * @return number of signals that were pending,
- * SIGNAL_ERROR if some error occured
- */
-int signal_clear(const dnbd3_signal_t* const signal);
-
-/**
- * Close the given signal.
- */
-void signal_close(const dnbd3_signal_t* const signal);
-
-/**
- * Get a file descriptor for the given signal that can be
- * waited on using poll or similar.
- * @return -1 if the signal is invalid
- */
-int signal_getWaitFd(const dnbd3_signal_t* const signal);
-
-#endif
diff --git a/src/shared/log.c b/src/shared/log.c
index 055acb4..3a4739d 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -3,7 +3,7 @@
*
* Copyright(c) 2011-2012 Simon Rettberg
*
- * This file may be licensed under the terms of of the
+ * This file may be licensed under the terms of the
* GNU General Public License Version 2 (the ``GPL'').
*
* Software distributed under the License is distributed
@@ -18,7 +18,7 @@
*
*/
-#include "log.h"
+#include <dnbd3/shared/log.h>
#include <stdarg.h>
#include <pthread.h>
#include <stdlib.h>
@@ -36,6 +36,7 @@ static _Atomic logmask_t maskCon = 15;
static char *logFile = NULL;
static int logFd = -1;
+static FILE *logOutStream;
static bool consoleTimestamps = false;
@@ -43,6 +44,10 @@ static bool consoleTimestamps = false;
static int writeLevel(char *buffer, logmask_t level);
+void log_init(void) {
+ logOutStream = stdout;
+}
+
bool log_hasMask(const logmask_t mask)
{
return ( ( maskFile | maskCon ) & mask ) == mask;
@@ -63,6 +68,15 @@ void log_setConsoleTimestamps(bool on)
consoleTimestamps = on;
}
+int log_setConsoleOutputStream(FILE *outputStream)
+{
+ if ( outputStream != stdout && outputStream != stderr )
+ return -EINVAL;
+
+ logOutStream = outputStream;
+ return 0;
+}
+
bool log_openLogFile(const char *path)
{
pthread_mutex_lock( &logLock );
@@ -93,10 +107,10 @@ void logadd(const logmask_t mask, const char *fmt, ...)
struct tm timeinfo;
char buffer[LINE_LEN];
bool toFile = maskFile & mask;
- bool toStdout = maskCon & mask;
+ bool toOutStream = maskCon & mask;
size_t offset;
- if ( toFile || ( toStdout && consoleTimestamps ) ) {
+ if ( toFile || ( toOutStream && consoleTimestamps ) ) {
time( &rawtime );
localtime_r( &rawtime, &timeinfo );
offset = strftime( buffer, LINE_LEN, "[%d.%m. %H:%M:%S] ", &timeinfo );
@@ -134,15 +148,11 @@ void logadd(const logmask_t mask, const char *fmt, ...)
}
pthread_mutex_unlock( &logLock );
}
- if ( toStdout ) {
- if ( consoleTimestamps ) stdoutLine = buffer;
-#ifdef AFL_MODE
- fputs( stdoutLine, stderr );
- fflush( stderr );
-#else
- fputs( stdoutLine, stdout );
- fflush( stdout );
-#endif
+ if ( toOutStream ) {
+ if ( consoleTimestamps )
+ stdoutLine = buffer;
+ fputs( stdoutLine, logOutStream );
+ fflush( logOutStream );
}
}
diff --git a/src/shared/log.h b/src/shared/log.h
deleted file mode 100644
index 5b1e8f7..0000000
--- a/src/shared/log.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This file is part of the Distributed Network Block Device 3
- *
- * Copyright(c) 2011-2012 Simon Rettberg
- *
- * This file may be licensed under the terms of of the
- * GNU General Public License Version 2 (the ``GPL'').
- *
- * Software distributed under the License is distributed
- * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
- * express or implied. See the GPL for the specific language
- * governing rights and limitations.
- *
- * You should have received a copy of the GPL along with this
- * program. If not, go to http://www.gnu.org/licenses/gpl.html
- * or write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef LOG_H_
-#define LOG_H_
-
-#include <stdbool.h>
-#include <unistd.h>
-
-typedef unsigned int logmask_t;
-#define LOG_ERROR ((logmask_t)1) // Fatal error, server will terminate
-#define LOG_WARNING ((logmask_t)2) // Major issue, something is broken but keep running
-#define LOG_MINOR ((logmask_t)4) // Minor issue, more of a hickup than serious problem
-#define LOG_INFO ((logmask_t)8) // Informational message
-#define LOG_DEBUG1 ((logmask_t)16) // Debug information, use this for non-spammy stuff
-#define LOG_DEBUG2 ((logmask_t)32) // Use this for debug messages that will show up a lot
-
-
-/**
- * Check if cansoleMask | fileMask has all of mask set.
- */
-bool log_hasMask(const logmask_t mask);
-
-void log_setFileMask(logmask_t mask);
-
-void log_setConsoleMask(logmask_t mask);
-
-void log_setConsoleTimestamps(bool on);
-
-/**
- * Open or reopen the log file. If path is NULL and the
- * function was called with a path before, the same path
- * will be used again.
- */
-bool log_openLogFile(const char *path);
-
-/**
- * Add a line to the log
- */
-void logadd(const logmask_t mask, const char *text, ...)
- __attribute__ ((format (printf, 2, 3)));
-
-/**
- * Return last size bytes of log.
- */
-ssize_t log_fetch(char *buffer, int size);
-
-#endif /* LOG_H_ */
diff --git a/src/shared/protocol.h b/src/shared/protocol.h
deleted file mode 100644
index 92dbe11..0000000
--- a/src/shared/protocol.h
+++ /dev/null
@@ -1,159 +0,0 @@
-#ifndef _PROTOCOL_H_
-#define _PROTOCOL_H_
-
-#include "sockhelper.h"
-
-#include "../types.h"
-#include "../serialize.h"
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-// Client tells server that it is another server
-#define FLAGS8_SERVER (1)
-// Client (which is a proxy) tells server that it has background-replication enabled
-#define FLAGS8_BG_REP (2)
-
-// 2017-10-16: We now support hop-counting, macro to pass hop count conditinally to a function
-#define COND_HOPCOUNT(vers,hopcount) ( (vers) >= 3 ? (hopcount) : 0 )
-
-// 2017-11-02: Macro to set flags in select image message properly if we're a server, as BG_REP depends on global var
-#define SI_SERVER_FLAGS ( (_pretendClient ? 0 : FLAGS8_SERVER) | (_backgroundReplication == BGR_FULL ? FLAGS8_BG_REP : 0) )
-
-#define REPLY_OK (0)
-#define REPLY_ERRNO (-1)
-#define REPLY_AGAIN (-2)
-#define REPLY_INTR (-3)
-#define REPLY_CLOSED (-4)
-#define REPLY_INCOMPLETE (-5)
-#define REPLY_WRONGMAGIC (-6)
-
-static inline int dnbd3_read_reply(int sock, dnbd3_reply_t *reply, bool wait)
-{
- ssize_t ret = recv( sock, reply, sizeof(*reply), (wait ? MSG_WAITALL : MSG_DONTWAIT) | MSG_NOSIGNAL );
- if ( ret == 0 ) return REPLY_CLOSED;
- if ( ret < 0 ) {
- if ( errno == EAGAIN || errno == EWOULDBLOCK ) return REPLY_AGAIN;
- if ( errno == EINTR ) return REPLY_INTR;
- return REPLY_ERRNO;
- }
- if ( !wait && ret != sizeof(*reply) ) ret += recv( sock, ((char*)reply) + ret, sizeof(*reply) - ret, MSG_WAITALL | MSG_NOSIGNAL );
- if ( ret != sizeof(*reply) ) return REPLY_INCOMPLETE;
- fixup_reply( *reply );
- if ( reply->magic != dnbd3_packet_magic ) return REPLY_WRONGMAGIC;
- return REPLY_OK;
-}
-
-static inline bool dnbd3_get_reply(int sock, dnbd3_reply_t *reply)
-{
- int ret;
- do {
- ret = dnbd3_read_reply( sock, reply, true );
- } while ( ret == REPLY_INTR );
- return ret == REPLY_OK;
-}
-
-static inline bool dnbd3_select_image(int sock, const char *name, uint16_t rid, uint8_t flags8)
-{
- serialized_buffer_t serialized;
- dnbd3_request_t request;
- struct iovec iov[2];
- serializer_reset_write( &serialized );
- serializer_put_uint16( &serialized, PROTOCOL_VERSION );
- serializer_put_string( &serialized, name );
- serializer_put_uint16( &serialized, rid );
- serializer_put_uint8( &serialized, flags8 );
- const ssize_t len = serializer_get_written_length( &serialized );
- request.magic = dnbd3_packet_magic;
- request.cmd = CMD_SELECT_IMAGE;
- request.size = (uint32_t)len;
-#ifdef _DEBUG
- request.handle = 0;
- request.offset = 0;
-#endif
- fixup_request( request );
- iov[0].iov_base = &request;
- iov[0].iov_len = sizeof(request);
- iov[1].iov_base = &serialized;
- iov[1].iov_len = len;
- ssize_t ret;
- do {
- ret = writev( sock, iov, 2 );
- } while ( ret == -1 && errno == EINTR );
- return ret == len + (ssize_t)sizeof(request);
-}
-
-static inline bool dnbd3_get_block(int sock, uint64_t offset, uint32_t size, uint64_t handle, uint8_t hopCount)
-{
- dnbd3_request_t request;
- request.magic = dnbd3_packet_magic;
- request.handle = handle;
- request.cmd = CMD_GET_BLOCK;
- // When writing before "fixup", we can get away with assigning to offset instead of offset_small if we
- // do it before assigning to .hops. Faster on 64bit machines (so, on everything)
- request.offset = offset;
- request.hops = hopCount;
- request.size = size;
- fixup_request( request );
- return sock_sendAll( sock, &request, sizeof(request), 2 ) == (ssize_t)sizeof(request);
-}
-
-static inline bool dnbd3_get_crc32(int sock, uint32_t *master, void *buffer, size_t *bufferLen)
-{
- dnbd3_request_t request;
- dnbd3_reply_t reply;
- request.magic = dnbd3_packet_magic;
- request.handle = 0;
- request.cmd = CMD_GET_CRC32;
- request.offset = 0;
- request.size = 0;
- fixup_request( request );
- if ( sock_sendAll( sock, &request, sizeof(request), 2 ) != (ssize_t)sizeof(request) ) return false;
- if ( !dnbd3_get_reply( sock, &reply ) ) return false;
- if ( reply.size == 0 ) {
- *bufferLen = 0;
- return true;
- }
- if ( reply.size < 4 ) return false;
- reply.size -= 4;
- if ( reply.cmd != CMD_GET_CRC32 || reply.size > *bufferLen ) return false;
- *bufferLen = reply.size;
- if ( sock_recv( sock, master, sizeof(uint32_t) ) != (ssize_t)sizeof(uint32_t) ) return false;
- return sock_recv( sock, buffer, reply.size ) == (ssize_t)reply.size;
-}
-
-/**
- * Pass a full serialized_buffer_t and a socket fd. Parsed data will be returned in further arguments.
- * Note that all strings will point into the passed buffer, so there's no need to free them.
- * This function will also read the header for you, as this message can only occur during connection,
- * where no unrequested messages could arrive inbetween.
- */
-static inline bool dnbd3_select_image_reply(serialized_buffer_t *buffer, int sock, uint16_t *protocol_version, char **name, uint16_t *rid,
- uint64_t *imageSize)
-{
- errno = 0;
- dnbd3_reply_t reply;
- if ( !dnbd3_get_reply( sock, &reply ) ) {
- return false;
- }
- errno = 0;
- if ( reply.cmd != CMD_SELECT_IMAGE || reply.size < 3 || reply.size > MAX_PAYLOAD ) {
- return false;
- }
- // receive reply payload
- ssize_t ret = sock_recv( sock, buffer, reply.size );
- if ( ret != (ssize_t)reply.size ) {
- return false;
- }
- // handle/check reply payload
- serializer_reset_read( buffer, reply.size );
- *protocol_version = serializer_get_uint16( buffer );
- *name = serializer_get_string( buffer );
- *rid = serializer_get_uint16( buffer );
- *imageSize = serializer_get_uint64( buffer );
- return true;
-}
-
-#endif
diff --git a/src/shared/serialize.c b/src/shared/serialize.c
new file mode 100644
index 0000000..1f7cddd
--- /dev/null
+++ b/src/shared/serialize.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <dnbd3/shared/serialize.h>
+#include <dnbd3/types.h>
+
+void serializer_reset_read(serialized_buffer_t *buffer, size_t data_len)
+{
+ buffer->buffer_end = buffer->buffer + MIN(MAX_PAYLOAD, data_len);
+ buffer->buffer_pointer = buffer->buffer;
+}
+
+void serializer_reset_write(serialized_buffer_t *buffer)
+{
+ buffer->buffer_end = buffer->buffer + MAX_PAYLOAD;
+ buffer->buffer_pointer = buffer->buffer;
+}
+
+uint8_t serializer_get_uint8(serialized_buffer_t *buffer)
+{
+ if (buffer->buffer_pointer + 1 > buffer->buffer_end)
+ return 0;
+ return (uint8_t)*buffer->buffer_pointer++;
+}
+
+uint16_t serializer_get_uint16(serialized_buffer_t *buffer)
+{
+ uint16_t ret;
+
+ if (buffer->buffer_pointer + 2 > buffer->buffer_end)
+ return 0;
+ memcpy(&ret, buffer->buffer_pointer, 2);
+ buffer->buffer_pointer += 2;
+ return net_order_16(ret);
+}
+
+uint64_t serializer_get_uint64(serialized_buffer_t *buffer)
+{
+ uint64_t ret;
+
+ if (buffer->buffer_pointer + 8 > buffer->buffer_end)
+ return 0;
+ memcpy(&ret, buffer->buffer_pointer, 8);
+ buffer->buffer_pointer += 8;
+ return net_order_64(ret);
+}
+
+char *serializer_get_string(serialized_buffer_t *buffer)
+{
+ char *ptr = buffer->buffer_pointer, *start = buffer->buffer_pointer;
+
+ if (ptr >= buffer->buffer_end)
+ return NULL;
+ while (ptr < buffer->buffer_end && *ptr)
+ ++ptr;
+ // String did not terminate within buffer (possibly corrupted/malicious packet)
+ if (*ptr)
+ return NULL;
+ buffer->buffer_pointer = ptr + 1;
+ return start;
+}
+
+void serializer_put_uint8(serialized_buffer_t *buffer, uint8_t value)
+{
+ if (buffer->buffer_pointer + 1 > buffer->buffer_end)
+ return;
+ *buffer->buffer_pointer++ = (char)value;
+}
+
+void serializer_put_uint16(serialized_buffer_t *buffer, uint16_t value)
+{
+ if (buffer->buffer_pointer + 2 > buffer->buffer_end)
+ return;
+ value = net_order_16(value);
+ memcpy(buffer->buffer_pointer, &value, 2);
+ buffer->buffer_pointer += 2;
+}
+
+void serializer_put_uint64(serialized_buffer_t *buffer, uint64_t value)
+{
+ if (buffer->buffer_pointer + 8 > buffer->buffer_end)
+ return;
+ value = net_order_64(value);
+ memcpy(buffer->buffer_pointer, &value, 8);
+ buffer->buffer_pointer += 8;
+}
+
+void serializer_put_string(serialized_buffer_t *buffer, const char *value)
+{
+ const size_t len = strlen(value) + 1;
+
+ if (buffer->buffer_pointer + len > buffer->buffer_end)
+ return;
+ memcpy(buffer->buffer_pointer, value, len);
+ buffer->buffer_pointer += len;
+}
+
+uint32_t serializer_get_written_length(serialized_buffer_t *buffer)
+{
+ return (uint32_t)(buffer->buffer_pointer - buffer->buffer);
+}
diff --git a/src/shared/sockhelper.c b/src/shared/sockhelper.c
index ab34aa1..5096320 100644
--- a/src/shared/sockhelper.c
+++ b/src/shared/sockhelper.c
@@ -1,6 +1,8 @@
-#include "sockhelper.h"
-#include "log.h"
+#include <dnbd3/shared/sockhelper.h>
+#include <dnbd3/shared/log.h>
+#include <dnbd3/types.h>
#include <arpa/inet.h> // inet_ntop
+#include <netinet/tcp.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
@@ -19,8 +21,7 @@ struct _poll_list {
int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const int rw_ms)
{
// TODO: Move out of here, this unit should contain general socket functions
- // TODO: Abstract away from sockaddr_in* like the rest of the functions here do,
- // so WITH_IPV6 can finally be removed as everything is transparent. b- but how?
+ // TODO: Abstract away from sockaddr_in* like the rest of the functions here
struct sockaddr_storage ss;
int proto, addrlen;
memset( &ss, 0, sizeof ss );
@@ -32,9 +33,7 @@ int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const in
addr4->sin_port = addr->port;
proto = PF_INET;
addrlen = sizeof *addr4;
- }
-#ifdef WITH_IPV6
- else if ( addr->type == HOST_IP6 ) {
+ } else if ( addr->type == HOST_IP6 ) {
// Set host (IPv6)
struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&ss;
addr6->sin6_family = AF_INET6;
@@ -42,10 +41,9 @@ int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const in
addr6->sin6_port = addr->port;
proto = PF_INET6;
addrlen = sizeof *addr6;
- }
-#endif
- else {
+ } else {
logadd( LOG_DEBUG1, "Unsupported address type: %d\n", (int)addr->type );
+ errno = EAFNOSUPPORT;
return -1;
}
int client_sock = socket( proto, SOCK_STREAM, IPPROTO_TCP );
@@ -56,9 +54,13 @@ int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const in
} else {
sock_setTimeout( client_sock, connect_ms );
}
+ // NODELAY makes sense for the client side, which should be all users in this code base
+ int e2 = 1;
+ setsockopt( client_sock, IPPROTO_TCP, TCP_NODELAY, (void *)&e2, sizeof(e2) );
for ( int i = 0; i < 5; ++i ) {
int ret = connect( client_sock, (struct sockaddr *)&ss, addrlen );
- if ( ret != -1 || errno == EINPROGRESS || errno == EISCONN ) break;
+ e2 = errno;
+ if ( ret != -1 || ( connect_ms == -1 && errno == EINPROGRESS ) || errno == EISCONN ) break;
if ( errno == EINTR ) {
// http://www.madore.org/~david/computers/connect-intr.html
#ifdef __linux__
@@ -67,21 +69,26 @@ int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const in
struct pollfd unix_really_sucks = { .fd = client_sock, .events = POLLOUT | POLLIN };
while ( i-- > 0 ) {
int pr = poll( &unix_really_sucks, 1, connect_ms == 0 ? -1 : connect_ms );
+ e2 = errno;
if ( pr == 1 && ( unix_really_sucks.revents & POLLOUT ) ) break;
if ( pr == -1 && errno == EINTR ) continue;
close( client_sock );
+ errno = e2;
return -1;
}
- sockaddr_storage junk;
+ struct sockaddr_storage junk;
socklen_t more_junk = sizeof(junk);
if ( getpeername( client_sock, (struct sockaddr*)&junk, &more_junk ) == -1 ) {
+ e2 = errno;
close( client_sock );
+ errno = e2;
return -1;
}
break;
#endif
} // EINTR
close( client_sock );
+ errno = e2;
return -1;
}
if ( connect_ms != -1 && connect_ms != rw_ms ) {
@@ -157,7 +164,7 @@ bool sock_sockaddrToDnbd3(struct sockaddr* sa, dnbd3_host_t *host)
memcpy( host->addr, &addr4->sin_addr, 4 );
return true;
}
-#ifdef WITH_IPV6
+
if ( sa->sa_family == AF_INET6 ) {
// Set host (IPv6)
struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)sa;
@@ -166,7 +173,7 @@ bool sock_sockaddrToDnbd3(struct sockaddr* sa, dnbd3_host_t *host)
memcpy( host->addr, &addr6->sin6_addr, 16 );
return true;
}
-#endif
+
return false;
}
@@ -234,7 +241,10 @@ size_t sock_printable(const struct sockaddr * const addr, const socklen_t addrLe
outlen = snprintf( output, len, "[%s]:%s", host, port );
}
}
- if ( outlen <= 0 ) return 0;
+ if ( outlen <= 0 ) {
+ output[0] = '\0';
+ return 0;
+ }
return MIN( (size_t)outlen, len-1 );
}
@@ -338,7 +348,7 @@ int sock_multiConnect(poll_list_t* list, const dnbd3_host_t* host, int connect_m
if ( i != list->count ) list->entry[i] = list->entry[list->count];
if ( fd != -1 ) {
sock_set_block( fd );
- if ( rw_ms != -1 && rw_ms != connect_ms ) {
+ if ( rw_ms != -1 ) {
sock_setTimeout( fd, rw_ms );
}
return fd;
diff --git a/src/shared/sockhelper.h b/src/shared/sockhelper.h
deleted file mode 100644
index 8d70789..0000000
--- a/src/shared/sockhelper.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef SOCKHELPER_H_
-#define SOCKHELPER_H_
-
-/*
- * Helper functions for dealing with sockets. These functions should
- * abstract from the IP version by using getaddrinfo() and thelike.
- */
-
-#include "../types.h"
-#include <stdint.h>
-#include <sys/socket.h>
-#include <string.h>
-
-typedef struct _poll_list poll_list_t;
-
-/**
- * Connect to given dnbd3_host_t.
- * @param addr - address of host to connect to
- * @param connect_ms - timeout in milliseconds after which the connection attempt fails
- * @param rw_ms - read/write timeout in milliseconds to apply on successful connect
- * @return socket file descriptor, or -1 on error
- */
-int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const int rw_ms);
-
-/**
- * Resolve/parse given address and put the result(s) into passed dnbd3_host_t array,
- * but only up to count entries.
- * @return Number of items added to array
- */
-int sock_resolveToDnbd3Host(const char * const address, dnbd3_host_t * const dest, const int count);
-
-bool sock_sockaddrToDnbd3(struct sockaddr* sa, dnbd3_host_t *host);
-
-void sock_setTimeout(const int sockfd, const int milliseconds);
-
-size_t sock_printHost(const dnbd3_host_t * const host, char *output, const size_t len);
-
-size_t sock_printable(const struct sockaddr * const addr, const socklen_t addrLen, char *output, const size_t len);
-
-/**
- * Create new poll list.
- */
-poll_list_t* sock_newPollList();
-
-/**
- * Delete a poll list, closing all sockets first if necessary.
- */
-void sock_destroyPollList(poll_list_t *list);
-
-/**
- * Listen on all interfaces/available IP addresses, using the given protocol.
- * IPv4 and IPv6 are supported.
- * @param protocol_family PF_INET or PF_INET6
- * @param port port to listen on
- * @return true if any listen call was successful
- */
-bool sock_listenAny(poll_list_t* list, uint16_t port);
-
-/**
- * Listen on a specific address and port.
- * @param bind_addr human readable address to bind to for listening
- * @param port to listen on
- */
-bool sock_listen(poll_list_t* list, char* bind_addr, uint16_t port);
-
-/**
- * Asynchroneously connect to multiple hosts.
- * This can be called multiple times with varying timeouts. Calling it
- * the first time on an empty list is identical to sock_connect(). On
- * consecutive calls, more nonblocking sockets in connecting state will
- * be added to the list, and on each of these calls, all the pending
- * sockets will be checked for successful connection (or error), respecting
- * the passed timeout.
- * host can be NULL to just wait on the sockets already in the list.
- * If at least one socket completed the connection
- * within the given timeout, it will be removed from the list and
- * returned. On error or timeout, -1 is returned. If there are no more sockets
- * in the list, -2 is returned.
- */
-int sock_multiConnect(poll_list_t* list, const dnbd3_host_t* host, int connect_ms, int rw_ms);
-
-/**
- * This is a multi-socket version of accept. Pass in an array of listening sockets.
- * If any of the sockets has an incoming connection, accept it and return the new socket's fd.
- * On error, return -1, just like accept().
- * @param sockets array of listening socket fds
- * @param socket_count number of sockets in that array
- * @return fd of new client socket, -1 on error
- */
-int sock_accept(poll_list_t *list, struct sockaddr_storage *addr, socklen_t *length_ptr);
-
-void sock_set_nonblock(int sock);
-
-void sock_set_block(int sock);
-
-/**
- * Add given socket to array. Take an existing empty slot ( == -1) if available,
- * append to end otherwise. Updates socket count variable passed by reference.
- *
- * @param poll_list_t list the poll list to add the socket to
- * @param sock socket fd to add
- * @param wantRead whether to set the EPOLLIN flag
- * @param wantWrite whether to set the EPOLLOUT flag
- * @return true on success, false iff the array is already full or socket is < 0
- */
-bool sock_append(poll_list_t *list, const int sock, bool wantRead, bool wantWrite);
-
-/**
- * Send the whole buffer, calling write() multiple times if neccessary.
- * Give up after calling write() maxtries times.
- * Set maxtries < 0 to try infinitely.
- */
-ssize_t sock_sendAll(const int sock, const void *buffer, const size_t len, int maxtries);
-
-/**
- * Send given buffer, repeatedly calling recv on partial send or EINTR.
- */
-ssize_t sock_recv(const int sock, void *buffer, const size_t len);
-
-#endif /* SOCKHELPER_H_ */
diff --git a/src/shared/timing.c b/src/shared/timing.c
index 4ca1002..bdb8388 100644
--- a/src/shared/timing.c
+++ b/src/shared/timing.c
@@ -1,4 +1,4 @@
-#include "timing.h"
+#include <dnbd3/shared/timing.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/src/shared/timing.h b/src/shared/timing.h
deleted file mode 100644
index f3d8802..0000000
--- a/src/shared/timing.h
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef _D_TIMING_H
-#define _D_TIMING_H
-
-#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 199309L
-#endif
-
-#include <time.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef CLOCK_MONOTONIC_RAW
-#define BEST_CLOCK_SOURCE CLOCK_MONOTONIC_RAW
-#else
-#define BEST_CLOCK_SOURCE CLOCK_MONOTONIC
-#endif
-
-typedef struct timespec ticks;
-
-extern struct timespec basetime;
-
-/**
- * Assign src to dst while adding secs seconds.
- */
-#define timing_set(dst,src,secs) do { (dst)->tv_sec = (src)->tv_sec + secs; (dst)->tv_nsec = (src)->tv_nsec; } while (0)
-
-/**
- * Define variable now, initialize to timing_get.
- */
-#define declare_now ticks now; timing_get( &now )
-
-/**
- * Call this once to calibrate on startup.
- * Although overflows of CLOCK_MONOTONIC(_RAW) should
- * by definition never happen, we still have a fixed size
- * int that could at some point. By forcing the counter
- * to start at 0 on startup the point of overflow
- * will be very far in the future (decades for 32bit time_t,
- * end of universe for 64bit).
- */
-void timing_setBase();
-
-/**
- * Internal, do not use. Moved to another function
- * to prevent inlining of error handling code, which
- * should be very unlikely to ever trigger.
- */
-_Noreturn void timing_abort();
-
-/**
- * Get current time. Shortcut for clock_gettime with error check.
- */
-static inline void timing_get(ticks* retval)
-{
- if ( clock_gettime( BEST_CLOCK_SOURCE, retval ) == -1 ) timing_abort();
- retval->tv_sec -= basetime.tv_sec;
-}
-
-/**
- * Get a ticks instance somewhere in the future.
- * Useful for timeouts.
- */
-static inline void timing_gets(ticks* retval, int32_t addSeconds)
-{
- timing_get( retval );
- retval->tv_sec += addSeconds;
-}
-
-static inline void timing_addSeconds(ticks* retval, ticks* base, int32_t addSeconds)
-{
- retval->tv_sec = base->tv_sec + addSeconds;
- retval->tv_nsec = base->tv_nsec;
-}
-
-/**
- * Check whether given timeout is reached.
- * Might trigger up to one second early.
- */
-static inline bool timing_reached(const ticks* timeout, const ticks* now)
-{
- return now->tv_sec >= timeout->tv_sec;
-}
-#define timing_1le2(one,two) timing_reached(one,two)
-
-/**
- * Precise check whether given timeout has been reached.
- */
-static inline bool timing_reachedPrecise(const ticks* timeout, const ticks* now)
-{
- return now->tv_sec > timeout->tv_sec
- || (now->tv_sec == timeout->tv_sec && now->tv_nsec > timeout->tv_nsec);
-}
-
-/**
- * Shortcut for above. Useful if not used in loop.
- * Might trigger up to one second early.
- */
-static inline bool timing_isReached(const ticks* timeout)
-{
- ticks now;
- timing_get( &now );
- return timing_reached( timeout, &now );
-}
-/**
- * Shortcut for above. Useful if not used in loop.
- */
-static inline bool timing_isReachedPrecise(const ticks* timeout)
-{
- ticks now;
- timing_get( &now );
- return timing_reachedPrecise( timeout, &now );
-}
-
-
-/**
- * Get difference between two ticks, rounded down to seconds.
- * Make sure you pass the arguments in the proper order. If
- * end is before start, 0 will always be returned.
- */
-static inline uint32_t timing_diff(const ticks *start, const ticks *end)
-{
- if ( end->tv_sec <= start->tv_sec ) return 0;
- return (uint32_t)( ( end->tv_sec - start->tv_sec )
- + ( start->tv_nsec > end->tv_nsec ? -1 : 0 ) );
-}
-
-/**
- * Get difference between two ticks, rounded down to milliseconds.
- * Same as above; passing arguments in reverse will always return 0.
- */
-static inline uint64_t timing_diffMs(const ticks *start, const ticks *end)
-{
- if ( end->tv_sec < start->tv_sec ) return 0;
- uint64_t diff = (uint64_t)( end->tv_sec - start->tv_sec ) * 1000;
- if ( start->tv_nsec >= end->tv_nsec ) {
- if ( diff == 0 ) return 0;
- diff -= (start->tv_nsec - end->tv_nsec) / 1000000;
- } else {
- diff += (end->tv_nsec - start->tv_nsec) / 1000000;
- }
- return diff;
-}
-
-/**
- * Get difference between two ticks, rounded down to microseconds.
- * Same as above; passing arguments in reverse will always return 0.
- */
-static inline uint64_t timing_diffUs(const ticks *start, const ticks *end)
-{
- if ( end->tv_sec < start->tv_sec ) return 0;
- uint64_t diff = (uint64_t)( end->tv_sec - start->tv_sec ) * 1000000;
- if ( start->tv_nsec >= end->tv_nsec ) {
- if ( diff == 0 ) return 0;
- diff -= ( start->tv_nsec - end->tv_nsec ) / 1000;
- } else {
- diff += ( end->tv_nsec - start->tv_nsec ) / 1000;
- }
- return diff;
-}
-
-
-#endif