summaryrefslogtreecommitdiffstats
path: root/inc
diff options
context:
space:
mode:
authorManuel Bentele2020-10-16 17:15:49 +0200
committerManuel Bentele2020-10-16 17:15:49 +0200
commit969496f15e1e0359e26c2c6e995ad4ef82720f86 (patch)
tree358466216630eb10e8ee91b9ede490424f6db848 /inc
parent[FUSE] turn on compiler optimization to fix warning (diff)
downloaddnbd3-969496f15e1e0359e26c2c6e995ad4ef82720f86.tar.gz
dnbd3-969496f15e1e0359e26c2c6e995ad4ef82720f86.tar.xz
dnbd3-969496f15e1e0359e26c2c6e995ad4ef82720f86.zip
[BUILD] rewrite CMake build system to track changes of source files
This change restructures the source code directories, separates shared form non-shared application code and adds CMake dependencies. These dependencies allow the tracking of changes and trigger a rebuild of those build targets where changed files are involved. WARNING: Note that the support of the DNBD3_SERVER_AFL build option is not supported yet. Thus, the option should be never turned on.
Diffstat (limited to 'inc')
-rw-r--r--inc/dnbd3/config.h43
-rw-r--r--inc/dnbd3/config/client.h36
-rw-r--r--inc/dnbd3/config/server.h62
-rw-r--r--inc/dnbd3/shared/crc32.h9
-rw-r--r--inc/dnbd3/shared/fdsignal.h57
-rw-r--r--inc/dnbd3/shared/log.h65
-rw-r--r--inc/dnbd3/shared/protocol.h156
-rw-r--r--inc/dnbd3/shared/serialize.h40
-rw-r--r--inc/dnbd3/shared/sockhelper.h120
-rw-r--r--inc/dnbd3/shared/timing.h162
-rw-r--r--inc/dnbd3/types.h190
-rw-r--r--inc/dnbd3/version.h.in9
12 files changed, 949 insertions, 0 deletions
diff --git a/inc/dnbd3/config.h b/inc/dnbd3/config.h
new file mode 100644
index 0000000..50336af
--- /dev/null
+++ b/inc/dnbd3/config.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Distributed Network Block Device 3
+ *
+ * Copyright(c) 2011-2012 Johann Latocha <johann@latocha.de>
+ *
+ * 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 CONFIG_H_
+#define CONFIG_H_
+
+// +++++ Network +++++
+// Default port
+#define PORT 5003
+#define RPC_PORT (PORT+1)
+
+// No serialized payload allowed exceeding this many bytes (so actual data from client->server is not affected by this limit!)
+#define MAX_PAYLOAD 1000
+
+// Protocol version should be increased whenever new features/messages are added,
+// so either the client or server can run in compatibility mode, or they can
+// cancel the connection right away if the protocol has changed too much
+#define PROTOCOL_VERSION 3
+// 2017-10-16: Update to v3: Change header to support request hop-counting
+
+#define NUMBER_SERVERS 8 // Number of alt servers per image/device
+
+// +++++ Block Device +++++
+#define DNBD3_BLOCK_SIZE ((uint64_t)4096) // NEVER CHANGE THIS OR THE WORLD WILL END!
+
+#endif /* CONFIG_H_ */
diff --git a/inc/dnbd3/config/client.h b/inc/dnbd3/config/client.h
new file mode 100644
index 0000000..f35f673
--- /dev/null
+++ b/inc/dnbd3/config/client.h
@@ -0,0 +1,36 @@
+#ifndef _CLIENTCONFIG_H_
+#define _CLIENTCONFIG_H_
+
+// Which is the minimum protocol version the client expects from the server
+#define MIN_SUPPORTED_SERVER 2
+
+// in seconds if not stated otherwise (MS = milliseconds)
+#define SOCKET_TIMEOUT_CLIENT_DATA 2
+#define SOCKET_TIMEOUT_CLIENT_DISCOVERY 1
+
+#define RTT_THRESHOLD_FACTOR(us) (((us) * 2) / 3) // 2/3 = current to best must be 33% worse
+#define RTT_ABSOLUTE_THRESHOLD (80000) // Or 80ms worse
+#define RTT_UNREACHABLE 0x7FFFFFFul // Use this value for timeout/unreachable as RTT. Don't set too high or you might get overflows. 0x7FFFFFF = 134 seconds
+// This must be a power of two:
+#define RTT_BLOCK_SIZE 4096
+
+#define STARTUP_MODE_DURATION 30
+// Interval of several repeating tasks (in seconds)
+#define TIMER_INTERVAL_PROBE_STARTUP 4
+#define TIMER_INTERVAL_PROBE_NORMAL 22
+#define TIMER_INTERVAL_PROBE_PANIC 2
+#define TIMER_INTERVAL_KEEPALIVE_PACKET 6
+
+// Expect a keepalive response every X seconds
+#define SOCKET_KEEPALIVE_TIMEOUT 8
+
+// Number of unsuccessful alt_server probes before read errors are reported to the block layer
+// (ALL servers will be probed this many times)
+// Set to 0 to disable
+#define PROBE_COUNT_TIMEOUT 0
+
+// ++ Kernel module ++
+#define DEFAULT_READ_AHEAD_KB 512
+#define NUMBER_DEVICES 8
+
+#endif
diff --git a/inc/dnbd3/config/server.h b/inc/dnbd3/config/server.h
new file mode 100644
index 0000000..b6eee2c
--- /dev/null
+++ b/inc/dnbd3/config/server.h
@@ -0,0 +1,62 @@
+#ifndef _SERVERCONFIG_H_
+#define _SERVERCONFIG_H_
+
+#include <dnbd3/config.h>
+
+// +++++ Performance/memory related
+#define SERVER_MAX_CLIENTS 4000
+#define SERVER_MAX_IMAGES 5000
+#define SERVER_MAX_ALTS 50
+// +++++ Uplink handling (proxy mode)
+#define SERVER_GLOBAL_DUP_TIME 6 // How many seconds to wait before changing global fail counter again
+#define SERVER_BAD_UPLINK_MIN 10 // Thresold for fails at which we start ignoring the server occasionally
+#define SERVER_BAD_UPLINK_MAX 20 // Hard block server if it failed this many times
+#define SERVER_BAD_UPLINK_LOCAL_BLOCK 10 // If a server didn't supply the requested image this many times, block it for some time
+#define SERVER_BAD_UPLINK_IGNORE 180 // How many seconds is a server ignored
+#define UPLINK_MAX_QUEUE 500 // Maximum number of queued requests per uplink
+#define UPLINK_MAX_CLIENTS_PER_REQUEST 32 // Maximum number of clients that can attach to one uplink request
+#define SERVER_UPLINK_QUEUELEN_THRES 900 // Threshold where we start dropping incoming clients
+#define SERVER_MAX_PENDING_ALT_CHECKS 500 // Length of queue for pending alt checks requested by uplinks
+
+// Wait a maximum of 5 minutes before saving cache map (if data was received at all)
+#define CACHE_MAP_MAX_SAVE_DELAY 300
+// If more than 500MB have been received from uplink without saving cache map, do so
+#define CACHE_MAP_MAX_UNSAVED_BYTES ((uint64_t)500 * 1000 * 1000)
+
+// Time in ms to wait for a read/write call to complete on an uplink connection
+#define SOCKET_TIMEOUT_UPLINK 5000
+// Same for client connections. Be a bit more liberal here
+#define SOCKET_TIMEOUT_CLIENT 15000
+// When waiting for the next request header from client, allow the timeout from above
+// to expire this many times. This allows for greater idle times without also increasing
+// the timeout for cases where we wait for additional data or are actively sending a reply
+#define SOCKET_TIMEOUT_CLIENT_RETRIES 3
+
+#define SERVER_UPLINK_KEEPALIVE_INTERVAL 10 // (Seconds) Send keep-alive if nothing else is happening on the uplink
+#define SERVER_UPLINK_IDLE_TIMEOUT 1800 // (Seconds) Timeout after which we tear down an uplink connection if no blocks needed to be fetched
+
+// +++++ Other magic constants
+#define SERVER_RTT_PROBES 5 // How many probes to average over
+#define SERVER_RTT_INTERVAL_INIT 5 // Initial interval between probes
+#define SERVER_RTT_INTERVAL_MAX 45 // Maximum interval between probes
+#define SERVER_RTT_MAX_UNREACH 10 // If no server was reachable this many times, stop RTT measurements for a while
+#define SERVER_RTT_INTERVAL_FAILED 180 // Interval to use if no uplink server is reachable for above many times
+
+#define SERVER_REMOTE_IMAGE_CHECK_CACHETIME 120 // 2 minutes
+
+// Which is the minimum protocol version the server expects from the client
+#define MIN_SUPPORTED_CLIENT 2
+// Same for when we're a proxy talking to another server
+#define MIN_SUPPORTED_SERVER 2
+
+// Length of comment fields (for alt server etc.)
+#define COMMENT_LENGTH 120
+
+#define RTT_THRESHOLD_FACTOR(us) (((us) * 2) / 3) // 2/3 = current to best must be 33% worse
+#define RTT_UNREACHABLE 0x7FFFFFFu // Use this value for timeout/unreachable as RTT. Don't set too high or you might get overflows. 0x7FFFFFF = 134 seconds
+
+// How many seconds have to pass after the last client disconnected until the imagefd is closed
+#define UNUSED_FD_TIMEOUT 3600
+
+#endif
+
diff --git a/inc/dnbd3/shared/crc32.h b/inc/dnbd3/shared/crc32.h
new file mode 100644
index 0000000..00b8bdd
--- /dev/null
+++ b/inc/dnbd3/shared/crc32.h
@@ -0,0 +1,9 @@
+#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/inc/dnbd3/shared/fdsignal.h b/inc/dnbd3/shared/fdsignal.h
new file mode 100644
index 0000000..960a2a9
--- /dev/null
+++ b/inc/dnbd3/shared/fdsignal.h
@@ -0,0 +1,57 @@
+#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/inc/dnbd3/shared/log.h b/inc/dnbd3/shared/log.h
new file mode 100644
index 0000000..5b1e8f7
--- /dev/null
+++ b/inc/dnbd3/shared/log.h
@@ -0,0 +1,65 @@
+/*
+ * 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/inc/dnbd3/shared/protocol.h b/inc/dnbd3/shared/protocol.h
new file mode 100644
index 0000000..1dd47f8
--- /dev/null
+++ b/inc/dnbd3/shared/protocol.h
@@ -0,0 +1,156 @@
+#ifndef _PROTOCOL_H_
+#define _PROTOCOL_H_
+
+#include <dnbd3/types.h>
+#include <dnbd3/shared/serialize.h>
+#include <dnbd3/shared/sockhelper.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 ( (uint8_t)( (_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;
+ request.handle = 0;
+ request.offset = 0;
+ 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/inc/dnbd3/shared/serialize.h b/inc/dnbd3/shared/serialize.h
new file mode 100644
index 0000000..a7a1ced
--- /dev/null
+++ b/inc/dnbd3/shared/serialize.h
@@ -0,0 +1,40 @@
+#ifndef SERIALIZER_H_
+#define SERIALIZER_H_
+
+#include <dnbd3/config.h>
+#include <dnbd3/types.h>
+
+typedef struct
+{
+ char buffer[MAX_PAYLOAD]; // This MUST be the first member or send_reply() will blow up
+ char *buffer_end;
+ char *buffer_pointer;
+} serialized_buffer_t;
+
+void serializer_reset_read(serialized_buffer_t *buffer, size_t data_len);
+
+void serializer_reset_write(serialized_buffer_t *buffer);
+
+uint32_t serializer_get_written_length(serialized_buffer_t *buffer);
+
+//
+
+uint8_t serializer_get_uint8(serialized_buffer_t *buffer);
+
+uint16_t serializer_get_uint16(serialized_buffer_t *buffer);
+
+uint64_t serializer_get_uint64(serialized_buffer_t *buffer);
+
+char *serializer_get_string(serialized_buffer_t *buffer);
+
+//
+
+void serializer_put_uint8(serialized_buffer_t *buffer, uint8_t value);
+
+void serializer_put_uint16(serialized_buffer_t *buffer, uint16_t value);
+
+void serializer_put_uint64(serialized_buffer_t *buffer, uint64_t value);
+
+void serializer_put_string(serialized_buffer_t *buffer, const char *value);
+
+#endif
diff --git a/inc/dnbd3/shared/sockhelper.h b/inc/dnbd3/shared/sockhelper.h
new file mode 100644
index 0000000..5c7d903
--- /dev/null
+++ b/inc/dnbd3/shared/sockhelper.h
@@ -0,0 +1,120 @@
+#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 <dnbd3/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/inc/dnbd3/shared/timing.h b/inc/dnbd3/shared/timing.h
new file mode 100644
index 0000000..f23bfeb
--- /dev/null
+++ b/inc/dnbd3/shared/timing.h
@@ -0,0 +1,162 @@
+#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
diff --git a/inc/dnbd3/types.h b/inc/dnbd3/types.h
new file mode 100644
index 0000000..c7f335b
--- /dev/null
+++ b/inc/dnbd3/types.h
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the Distributed Network Block Device 3
+ *
+ * Copyright(c) 2011-2012 Johann Latocha <johann@latocha.de>
+ *
+ * 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 TYPES_H_
+#define TYPES_H_
+
+#include <dnbd3/config.h>
+#ifdef DNBD3_KERNEL_MODULE
+#include <linux/kernel.h>
+#include <linux/string.h>
+#else
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+#ifdef __GNUC__
+#define UNUSED __attribute__ ((unused))
+#else
+#error "Please add define for your compiler for UNUSED, or define to nothing for your compiler if not supported"
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#ifdef __linux__
+#define HAVE_THREAD_NAMES
+#endif
+
+#ifdef __FreeBSD__
+#ifndef MSG_MORE
+#define MSG_MORE 0
+#endif
+#ifndef POLLRDHUP
+#define POLLRDHUP 0x2000
+#endif
+#include <netinet/in.h>
+#endif
+
+#ifdef DNBD3_SERVER_AFL
+#define send(a,b,c,d) write(a,b,c)
+#define recv(a,b,c,d) read(a,b,c)
+#endif
+
+
+// ioctl
+#define DNBD3_MAGIC 'd'
+#define IOCTL_OPEN _IO(0xab, 1)
+#define IOCTL_CLOSE _IO(0xab, 2)
+#define IOCTL_SWITCH _IO(0xab, 3)
+#define IOCTL_ADD_SRV _IO(0xab, 4)
+#define IOCTL_REM_SRV _IO(0xab, 5)
+
+#if defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define dnbd3_packet_magic ((uint16_t)( (0x73 << 8) | (0x72) ))
+// Flip bytes around on big endian when putting stuff on the net
+#define net_order_64(a) ((uint64_t)((((a) & 0xFFull) << 56) | (((a) & 0xFF00ull) << 40) | (((a) & 0xFF0000ull) << 24) | (((a) & 0xFF000000ull) << 8) | (((a) & 0xFF00000000ull) >> 8) | (((a) & 0xFF0000000000ull) >> 24) | (((a) & 0xFF000000000000ull) >> 40) | (((a) & 0xFF00000000000000ull) >> 56)))
+#define net_order_32(a) ((uint32_t)((((a) & (uint32_t)0xFF) << 24) | (((a) & (uint32_t)0xFF00) << 8) | (((a) & (uint32_t)0xFF0000) >> 8) | (((a) & (uint32_t)0xFF000000) >> 24)))
+#define net_order_16(a) ((uint16_t)((((a) & (uint16_t)0xFF) << 8) | (((a) & (uint16_t)0xFF00) >> 8)))
+#define fixup_request(a) do { \
+ (a).cmd = net_order_16((a).cmd); \
+ (a).size = net_order_32((a).size); \
+ (a).offset = net_order_64((a).offset); \
+} while (0)
+#define fixup_reply(a) do { \
+ (a).cmd = net_order_16((a).cmd); \
+ (a).size = net_order_32((a).size); \
+} while (0)
+#define ENDIAN_MODE "Big Endian"
+#define DNBD3_BIG_ENDIAN
+#elif defined(__LITTLE_ENDIAN__) || (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || defined(__i386__) || defined(__i386) || defined(__x86_64)
+#define dnbd3_packet_magic ((uint16_t)( (0x73) | (0x72 << 8) ))
+// Make little endian our network byte order as probably 99.999% of machines this will be used on are LE
+#define net_order_64(a) (a)
+#define net_order_32(a) (a)
+#define net_order_16(a) (a)
+#define fixup_request(a) while(0)
+#define fixup_reply(a) while(0)
+#define ENDIAN_MODE "Little Endian"
+#define DNBD3_LITTLE_ENDIAN
+#else
+#error "Unknown Endianness"
+#endif
+
+typedef uint8_t dnbd3_af;
+
+static const dnbd3_af HOST_NONE = (dnbd3_af)0;
+static const dnbd3_af HOST_IP4 = (dnbd3_af)2;
+static const dnbd3_af HOST_IP6 = (dnbd3_af)10;
+
+typedef struct __attribute__((packed)) dnbd3_host_t
+{
+ uint8_t addr[16]; // 16byte (network representation, so it can be directly passed to socket functions)
+ uint16_t port; // 2byte (network representation, so it can be directly passed to socket functions)
+ dnbd3_af type; // 1byte (ip version. HOST_IP4 or HOST_IP6. 0 means this struct is empty and should be ignored)
+} dnbd3_host_t;
+
+typedef struct __attribute__((packed))
+{
+ uint16_t len;
+ dnbd3_host_t host;
+ uint16_t imgnamelen;
+ char *imgname;
+ int rid;
+ int read_ahead_kb;
+ uint8_t use_server_provided_alts;
+} dnbd3_ioctl_t;
+
+// network
+#define CMD_GET_BLOCK 1
+#define CMD_SELECT_IMAGE 2
+#define CMD_GET_SERVERS 3
+#define CMD_ERROR 4
+#define CMD_KEEPALIVE 5
+#define CMD_LATEST_RID 6
+#define CMD_SET_CLIENT_MODE 7
+#define CMD_GET_CRC32 8
+
+#define DNBD3_REQUEST_SIZE 24
+typedef struct __attribute__((packed))
+{
+ uint16_t magic; // 2byte
+ uint16_t cmd; // 2byte
+ uint32_t size; // 4byte
+ union {
+ struct {
+#ifdef DNBD3_LITTLE_ENDIAN
+ uint64_t offset_small:56; // 7byte
+ uint8_t hops; // 1byte
+#elif defined(DNBD3_BIG_ENDIAN)
+ uint8_t hops; // 1byte
+ uint64_t offset_small:56; // 7byte
+#endif
+ };
+ uint64_t offset; // 8byte
+ };
+ uint64_t handle; // 8byte
+} dnbd3_request_t;
+_Static_assert( sizeof(dnbd3_request_t) == DNBD3_REQUEST_SIZE, "dnbd3_request_t is messed up" );
+
+#define DNBD3_REPLY_SIZE 16
+typedef struct __attribute__((packed))
+{
+ uint16_t magic; // 2byte
+ uint16_t cmd; // 2byte
+ uint32_t size; // 4byte
+ uint64_t handle; // 8byte
+} dnbd3_reply_t;
+_Static_assert( sizeof(dnbd3_reply_t) == DNBD3_REPLY_SIZE, "dnbd3_reply_t is messed up" );
+
+typedef struct __attribute__((packed))
+{
+ dnbd3_host_t host;
+ uint8_t failures; // 1byte (number of times server has been consecutively unreachable)
+} dnbd3_server_entry_t;
+
+#endif /* TYPES_H_ */
diff --git a/inc/dnbd3/version.h.in b/inc/dnbd3/version.h.in
new file mode 100644
index 0000000..4a88cf0
--- /dev/null
+++ b/inc/dnbd3/version.h.in
@@ -0,0 +1,9 @@
+/*
+ * AUTOGENERATED: DO NOT EDIT THIS FILE
+ */
+#ifndef VERSION_H_
+#define VERSION_H_
+
+#define DNBD3_VERSION "@DNBD3_VERSION@"
+
+#endif /* VERSION_H_ */