summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Rettberg2017-10-17 12:08:55 +0200
committerSimon Rettberg2017-10-17 12:08:55 +0200
commit102705470366b871109d2c3bf182c151ab71eb01 (patch)
treeb174c068ab12967491ff78458523c842b04f7b92 /src
parent[SERVER] rpc: Support querying storage size + available space (diff)
downloaddnbd3-102705470366b871109d2c3bf182c151ab71eb01.tar.gz
dnbd3-102705470366b871109d2c3bf182c151ab71eb01.tar.xz
dnbd3-102705470366b871109d2c3bf182c151ab71eb01.zip
[*] Support hop-counting in request header, protocol version 3
We steal 8 bits from the request offset to count hops when requests get relayed by proxies. This still leaves plenty of bits for the offset (56 bits, supporting images of up to 72 petabytes). This is used to detect proxy cycles. The algorithm is not perfect but should prevent endless relays of the same request. This is backwards compatible to old clients and servers, as the server only ever sets the hopcount in relayed requests if the upstream server is using protocol version 3 or newer, and clients are automatically upwards compatible as there is practically no image larger than 74PB, so the newly introduced hop count field is always 0 even in requests from old clients.
Diffstat (limited to 'src')
-rw-r--r--src/config.h3
-rw-r--r--src/fuse/connection.c6
-rw-r--r--src/server/altservers.c5
-rw-r--r--src/server/globals.h9
-rw-r--r--src/server/image.c6
-rw-r--r--src/server/net.c25
-rw-r--r--src/server/uplink.c47
-rw-r--r--src/server/uplink.h4
-rw-r--r--src/shared/protocol.h8
-rw-r--r--src/types.h33
10 files changed, 101 insertions, 45 deletions
diff --git a/src/config.h b/src/config.h
index 9f8ee10..50336af 100644
--- a/src/config.h
+++ b/src/config.h
@@ -32,7 +32,8 @@
// 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 2
+#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
diff --git a/src/fuse/connection.c b/src/fuse/connection.c
index 3f142c7..a3007fd 100644
--- a/src/fuse/connection.c
+++ b/src/fuse/connection.c
@@ -203,7 +203,7 @@ bool connection_read(dnbd3_async_t *request)
pthread_mutex_lock( &connection.sendMutex );
enqueueRequest( request );
if ( connection.sockFd != -1 ) {
- if ( !dnbd3_get_block( connection.sockFd, request->offset, request->length, (uint64_t)request ) ) {
+ if ( !dnbd3_get_block( connection.sockFd, request->offset, request->length, (uint64_t)request, 0 ) ) {
shutdown( connection.sockFd, SHUT_RDWR );
connection.sockFd = -1;
pthread_mutex_unlock( &connection.sendMutex );
@@ -501,7 +501,7 @@ static void probeAltServers()
srv->consecutiveFails += 10;
goto fail;
}
- if ( !dnbd3_get_block( sock, 0, RTT_BLOCK_SIZE, 0 ) ) {
+ if ( !dnbd3_get_block( sock, 0, RTT_BLOCK_SIZE, 0, 0 ) ) {
logadd( LOG_DEBUG1, "-> block request fail" );
goto fail;
}
@@ -637,7 +637,7 @@ static void switchConnection(int sockFd, alt_server_t *srv)
logadd( LOG_DEBUG1, "Requeue after server change" );
next = it->next;
enqueueRequest( it );
- if ( connection.sockFd != -1 && !dnbd3_get_block( connection.sockFd, it->offset, it->length, (uint64_t)it ) ) {
+ if ( connection.sockFd != -1 && !dnbd3_get_block( connection.sockFd, it->offset, it->length, (uint64_t)it, 0 ) ) {
logadd( LOG_WARNING, "Resending pending request failed, re-entering panic mode" );
shutdown( connection.sockFd, SHUT_RDWR );
connection.sockFd = -1;
diff --git a/src/server/altservers.c b/src/server/altservers.c
index bf9d8f2..1e4af7e 100644
--- a/src/server/altservers.c
+++ b/src/server/altservers.c
@@ -407,6 +407,7 @@ static void *altservers_main(void *data UNUSED)
// Test them all
int bestSock = -1;
int bestIndex = -1;
+ int bestProtocolVersion = -1;
unsigned int bestRtt = 0xfffffff;
unsigned int currentRtt = 0xfffffff;
for (itAlt = 0; itAlt < numAlts; ++itAlt) {
@@ -439,7 +440,7 @@ static void *altservers_main(void *data UNUSED)
imageSize, image->virtualFilesize, image->name );
}
// Request first block (NOT random!) ++++++++++++++++++++++++++++++
- if ( !dnbd3_get_block( sock, 0, DNBD3_BLOCK_SIZE, 0 ) ) {
+ if ( !dnbd3_get_block( sock, 0, DNBD3_BLOCK_SIZE, 0, COND_HOPCOUNT( protocolVersion, 1 ) ) ) {
ERROR_GOTO( server_failed, "[RTT] Could not request first block for %s", image->name );
}
// See if requesting the block succeeded ++++++++++++++++++++++
@@ -471,6 +472,7 @@ static void *altservers_main(void *data UNUSED)
bestSock = sock;
bestRtt = avg;
bestIndex = itAlt;
+ bestProtocolVersion = protocolVersion;
} else {
// Was too slow, ignore
close( sock );
@@ -492,6 +494,7 @@ static void *altservers_main(void *data UNUSED)
spin_lock( &uplink->rttLock );
uplink->betterFd = bestSock;
uplink->betterServer = servers[bestIndex];
+ uplink->betterVersion = bestProtocolVersion;
uplink->rttTestResult = RTT_DOCHANGE;
spin_unlock( &uplink->rttLock );
signal_call( uplink->signal );
diff --git a/src/server/globals.h b/src/server/globals.h
index 379fb8d..b1740f4 100644
--- a/src/server/globals.h
+++ b/src/server/globals.h
@@ -21,7 +21,7 @@ typedef struct _dnbd3_client dnbd3_client_t;
// Must only be set in uplink_request()
#define ULR_NEW 1
// Slot is occupied, reply has not yet been received, matching request can safely rely on reuse.
-// Must only be set in uplink_mainloop()
+// Must only be set in uplink_mainloop() or uplink_request()
#define ULR_PENDING 2
// Slot is being processed, do not consider for hop on.
// Must only be set in uplink_handle_receive()
@@ -34,6 +34,7 @@ typedef struct
dnbd3_client_t * client; // Client to send reply to
int status; // status of this entry: ULR_*
time_t entered; // When this request entered the queue (for debugging)
+ uint8_t hopCount; // How many hops this request has already taken across proxies
} dnbd3_queued_request_t;
#define RTT_IDLE 0 // Not in progress
@@ -44,16 +45,16 @@ typedef struct
struct _dnbd3_connection
{
int fd; // socket fd to remote server
+ int version; // remote server protocol version
dnbd3_signal_t* signal; // used to wake up the process
pthread_t thread; // thread holding the connection
pthread_spinlock_t queueLock; // lock for synchronization on request queue etc.
- dnbd3_queued_request_t queue[SERVER_MAX_UPLINK_QUEUE];
- int queueLen; // length of queue
dnbd3_image_t *image; // image that this uplink is used for; do not call get/release for this pointer
dnbd3_host_t currentServer; // Current server we're connected to
pthread_spinlock_t rttLock; // When accessing rttTestResult, betterFd or betterServer
int rttTestResult; // RTT_*
dnbd3_host_t betterServer; // The better server
+ int betterVersion; // protocol version of better server
int betterFd; // Active connection to better server, ready to use
uint8_t *recvBuffer; // Buffer for receiving payload
uint32_t recvBufferLen; // Len of ^^
@@ -62,6 +63,8 @@ struct _dnbd3_connection
int nextReplicationIndex; // Which index in the cache map we should start looking for incomplete blocks at
uint64_t replicationHandle; // Handle of pending replication request
uint64_t bytesReceived; // Number of bytes received by the connection.
+ int queueLen; // length of queue
+ dnbd3_queued_request_t queue[SERVER_MAX_UPLINK_QUEUE];
};
typedef struct
diff --git a/src/server/image.c b/src/server/image.c
index 36e0f0c..78de2bb 100644
--- a/src/server/image.c
+++ b/src/server/image.c
@@ -430,7 +430,7 @@ dnbd3_image_t* image_get(char *name, uint16_t revision, bool checkIfWorking)
}
}
if ( candidate->uplink == NULL && candidate->cacheFd != -1 ) {
- uplink_init( candidate, -1, NULL );
+ uplink_init( candidate, -1, NULL, -1 );
}
}
@@ -916,7 +916,7 @@ static bool image_load(char *base, char *path, int withUplink)
goto load_error;
}
if ( withUplink ) {
- uplink_init( image, -1, NULL );
+ uplink_init( image, -1, NULL, -1 );
}
}
@@ -1227,7 +1227,7 @@ server_fail: ;
image = image_get( name, remoteRid, false );
if ( image != NULL && uplinkSock != -1 && uplinkServer != NULL ) {
// If so, init the uplink and pass it the socket
- if ( !uplink_init( image, uplinkSock, uplinkServer ) ) {
+ if ( !uplink_init( image, uplinkSock, uplinkServer, remoteProtocolVersion ) ) {
close( uplinkSock );
} else {
// Clumsy busy wait, but this should only take as long as it takes to start a thread, so is it really worth using a signalling mechanism?
diff --git a/src/server/net.c b/src/server/net.c
index 86be7ef..acb3dbe 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -294,8 +294,9 @@ void* net_handleNewConnection(void *clientPtr)
if ( _shutdown ) break;
switch ( request.cmd ) {
- case CMD_GET_BLOCK:
- if ( request.offset >= image->virtualFilesize ) {
+ case CMD_GET_BLOCK:;
+ const uint64_t offset = request.offset_small; // Copy to full uint64 to prevent repeated masking
+ if ( offset >= image->virtualFilesize ) {
// Sanity check
logadd( LOG_WARNING, "Client %s requested non-existent block", client->hostName );
reply.size = 0;
@@ -303,7 +304,7 @@ void* net_handleNewConnection(void *clientPtr)
send_reply( client->sock, &reply, NULL );
break;
}
- if ( request.offset + request.size > image->virtualFilesize ) {
+ if ( offset + request.size > image->virtualFilesize ) {
// Sanity check
logadd( LOG_WARNING, "Client %s requested data block that extends beyond image size", client->hostName );
reply.size = 0;
@@ -314,8 +315,8 @@ void* net_handleNewConnection(void *clientPtr)
if ( request.size != 0 && image->cache_map != NULL ) {
// This is a proxyed image, check if we need to relay the request...
- start = request.offset & ~(uint64_t)(DNBD3_BLOCK_SIZE - 1);
- end = (request.offset + request.size + DNBD3_BLOCK_SIZE - 1) & ~(uint64_t)(DNBD3_BLOCK_SIZE - 1);
+ start = offset & ~(uint64_t)(DNBD3_BLOCK_SIZE - 1);
+ end = (offset + request.size + DNBD3_BLOCK_SIZE - 1) & ~(uint64_t)(DNBD3_BLOCK_SIZE - 1);
bool isCached = true;
spin_lock( &image->lock );
// Check again as we only aquired the lock just now
@@ -364,13 +365,13 @@ void* net_handleNewConnection(void *clientPtr)
}
spin_unlock( &image->lock );
if ( !isCached ) {
- if ( !uplink_request( client, request.handle, request.offset, request.size ) ) {
+ if ( !uplink_request( client, request.handle, offset, request.size, request.hops ) ) {
logadd( LOG_DEBUG1, "Could not relay uncached request from %s to upstream proxy, disabling image %s:%d",
client->hostName, image->name, image->rid );
image->working = false;
goto exit_client_cleanup;
}
- break; // DONE
+ break; // DONE, exit request.cmd switch
}
}
@@ -391,16 +392,16 @@ void* net_handleNewConnection(void *clientPtr)
if ( request.size != 0 ) {
// Send payload if request length > 0
size_t done = 0;
- off_t offset = (off_t)request.offset;
+ off_t foffset = (off_t)offset;
size_t realBytes;
- if ( request.offset + request.size <= image->realFilesize ) {
+ if ( offset + request.size <= image->realFilesize ) {
realBytes = request.size;
} else {
- realBytes = image->realFilesize - request.offset;
+ realBytes = image->realFilesize - offset;
}
while ( done < realBytes ) {
#ifdef __linux__
- const ssize_t ret = sendfile( client->sock, image_file, &offset, realBytes - done );
+ const ssize_t ret = sendfile( client->sock, image_file, &foffset, realBytes - done );
if ( ret <= 0 ) {
const int err = errno;
if ( lock ) pthread_mutex_unlock( &client->sendMutex );
@@ -420,7 +421,7 @@ void* net_handleNewConnection(void *clientPtr)
done += ret;
#elif defined(__FreeBSD__)
off_t sent;
- int ret = sendfile( image_file, client->sock, offset, realBytes - done, NULL, &sent, 0 );
+ int ret = sendfile( image_file, client->sock, foffset, realBytes - done, NULL, &sent, 0 );
const int err = errno;
if ( ret < 0 ) {
if ( err == EAGAIN ) {
diff --git a/src/server/uplink.c b/src/server/uplink.c
index a8d2f0b..65cefb5 100644
--- a/src/server/uplink.c
+++ b/src/server/uplink.c
@@ -43,7 +43,7 @@ uint64_t uplink_getTotalBytesReceived()
* image. Uplinks run in their own thread.
* Locks on: _images[].lock
*/
-bool uplink_init(dnbd3_image_t *image, int sock, dnbd3_host_t *host)
+bool uplink_init(dnbd3_image_t *image, int sock, dnbd3_host_t *host, int version)
{
if ( !_isProxy ) return false;
dnbd3_connection_t *link = NULL;
@@ -72,6 +72,7 @@ bool uplink_init(dnbd3_image_t *image, int sock, dnbd3_host_t *host)
link->betterFd = sock;
link->betterServer = *host;
link->rttTestResult = RTT_DOCHANGE;
+ link->betterVersion = version;
} else {
link->betterFd = -1;
link->rttTestResult = RTT_IDLE;
@@ -145,7 +146,7 @@ void uplink_removeClient(dnbd3_connection_t *uplink, dnbd3_client_t *client)
* Request a chunk of data through an uplink server
* Locks on: image.lock, uplink.queueLock
*/
-bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uint32_t length)
+bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uint32_t length, uint8_t hops)
{
if ( client == NULL || client->image == NULL ) return false;
spin_lock( &client->image->lock );
@@ -161,9 +162,10 @@ bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uin
return false;
}
// Check if the client is the same host as the uplink. If so assume this is a circular proxy chain
- if ( isSameAddress( &uplink->currentServer, &client->host ) ) {
+ // This might be a false positive if there are multiple instances running on the same host (IP)
+ if ( hops != 0 && isSameAddress( &uplink->currentServer, &client->host ) ) {
spin_unlock( &client->image->lock );
- logadd( LOG_DEBUG1, "Proxy cycle detected" );
+ logadd( LOG_WARNING, "Proxy cycle detected (same host)." );
return false;
}
@@ -171,19 +173,34 @@ bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uin
int existingType = -1; // ULR_* type of existing request
int i;
int freeSlot = -1;
+ bool requestLoop = false;
const uint64_t end = start + length;
spin_lock( &uplink->queueLock );
spin_unlock( &client->image->lock );
for (i = 0; i < uplink->queueLen; ++i) {
- if ( freeSlot == -1 && uplink->queue[i].status == ULR_FREE ) freeSlot = i;
+ if ( freeSlot == -1 && uplink->queue[i].status == ULR_FREE ) {
+ freeSlot = i;
+ continue;
+ }
if ( uplink->queue[i].status != ULR_PENDING && uplink->queue[i].status != ULR_NEW ) continue;
- if ( (foundExisting == -1 || existingType == ULR_PENDING) && uplink->queue[i].from <= start && uplink->queue[i].to >= end ) {
- foundExisting = i;
- existingType = uplink->queue[i].status;
- break;
+ if ( uplink->queue[i].from <= start && uplink->queue[i].to >= end ) {
+ if ( hops > uplink->queue[i].hopCount ) {
+ requestLoop = true;
+ break;
+ }
+ if ( foundExisting == -1 || existingType == ULR_PENDING ) {
+ foundExisting = i;
+ existingType = uplink->queue[i].status;
+ if ( freeSlot != -1 ) break;
+ }
}
}
+ if ( requestLoop ) {
+ spin_unlock( &uplink->queueLock );
+ logadd( LOG_WARNING, "Rejecting relay of request to upstream proxy because of possible cyclic proxy chain. Incoming hop-count is %" PRIu8 ".", hops );
+ return false;
+ }
if ( freeSlot == -1 ) {
if ( uplink->queueLen >= SERVER_MAX_UPLINK_QUEUE ) {
spin_unlock( &uplink->queueLock );
@@ -198,7 +215,7 @@ bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uin
// a race condition where the reply for the outstanding request already arrived and the uplink thread
// is currently traversing the request queue. As it is processing the queue from highest to lowest index, it might
// already have passed the index of the free slot we determined, but not reached the existing request we just found above.
- if ( foundExisting != -1 && existingType != ULR_NEW && freeSlot > foundExisting ) foundExisting = -1;
+ if ( foundExisting != -1 && existingType != ULR_NEW && freeSlot > foundExisting ) foundExisting = -1; // -1 means "send request"
#ifdef _DEBUG
if ( foundExisting != -1 ) {
logadd( LOG_DEBUG2, "%p (%s) Found existing request of type %s at slot %d, attaching in slot %d.\n", (void*)uplink, uplink->image->name, existingType == ULR_NEW ? "ULR_NEW" : "ULR_PENDING", foundExisting, freeSlot );
@@ -215,6 +232,7 @@ bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uin
uplink->queue[freeSlot].client = client;
//int old = uplink->queue[freeSlot].status;
uplink->queue[freeSlot].status = (foundExisting == -1 ? ULR_NEW : ULR_PENDING);
+ uplink->queue[freeSlot].hopCount = hops;
#ifdef _DEBUG
uplink->queue[freeSlot].entered = time( NULL );
//logadd( LOG_DEBUG2 %p] Inserting request at slot %d, was %d, now %d, handle %" PRIu64 ", Range: %" PRIu64 "-%" PRIu64 "\n", (void*)uplink, freeSlot, old, uplink->queue[freeSlot].status, uplink->queue[freeSlot, ".handle, start, end );
@@ -272,6 +290,7 @@ static void* uplink_mainloop(void *data)
link->fd = link->betterFd;
link->betterFd = -1;
link->currentServer = link->betterServer;
+ link->version = link->betterVersion;
spin_unlock( &link->rttLock );
discoverFailCount = 0;
if ( fd != -1 ) close( fd );
@@ -439,8 +458,10 @@ static void uplink_sendRequests(dnbd3_connection_t *link, bool newOnly)
link->queue[j].status = ULR_PENDING;
const uint64_t offset = link->queue[j].from;
const uint32_t size = link->queue[j].to - link->queue[j].from;
+ uint8_t hops = link->queue[j].hopCount;
spin_unlock( &link->queueLock );
- const int ret = dnbd3_get_block( link->fd, offset, size, offset );
+ if ( hops < 200 ) hops += 1;
+ const int ret = dnbd3_get_block( link->fd, offset, size, offset, COND_HOPCOUNT( link->version, hops ) );
if ( !ret ) {
// Non-critical - if the connection dropped or the server was changed
// the thread will re-send this request as soon as the connection
@@ -488,7 +509,7 @@ static void uplink_sendReplicationRequest(dnbd3_connection_t *link)
// Unlocked - do not break or continue here...
const uint64_t offset = link->replicationHandle = (uint64_t)i * (uint64_t)requestBlockSize;
const uint32_t size = MIN( image->realFilesize - offset, requestBlockSize );
- if ( !dnbd3_get_block( link->fd, offset, size, link->replicationHandle ) ) {
+ if ( !dnbd3_get_block( link->fd, offset, size, link->replicationHandle, COND_HOPCOUNT( link->version, 1 ) ) ) {
logadd( LOG_DEBUG1, "Error sending background replication request to uplink server!\n" );
return;
}
@@ -644,7 +665,7 @@ static void uplink_handleReceive(dnbd3_connection_t *link)
*/
static int uplink_sendKeepalive(const int fd)
{
- static dnbd3_request_t request = { 0, 0, 0, 0, 0 };
+ static dnbd3_request_t request = { 0 };
if ( request.magic == 0 ) {
request.magic = dnbd3_packet_magic;
request.cmd = CMD_KEEPALIVE;
diff --git a/src/server/uplink.h b/src/server/uplink.h
index c8cf4eb..2b41dfc 100644
--- a/src/server/uplink.h
+++ b/src/server/uplink.h
@@ -8,11 +8,11 @@ void uplink_globalsInit();
uint64_t uplink_getTotalBytesReceived();
-bool uplink_init(dnbd3_image_t *image, int sock, dnbd3_host_t *host);
+bool uplink_init(dnbd3_image_t *image, int sock, dnbd3_host_t *host, int version);
void uplink_removeClient(dnbd3_connection_t *uplink, dnbd3_client_t *client);
-bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uint32_t length);
+bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uint32_t length, uint8_t hopCount);
void uplink_shutdown(dnbd3_image_t *image);
diff --git a/src/shared/protocol.h b/src/shared/protocol.h
index eb1178d..c3ccbc1 100644
--- a/src/shared/protocol.h
+++ b/src/shared/protocol.h
@@ -13,6 +13,9 @@
#define FLAGS8_SERVER (1)
+// 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 )
+
#define REPLY_OK (0)
#define REPLY_ERRNO (-1)
#define REPLY_AGAIN (-2)
@@ -76,13 +79,16 @@ static inline bool dnbd3_select_image(int sock, const char *name, uint16_t rid,
return ret == len + (ssize_t)sizeof(request);
}
-static inline bool dnbd3_get_block(int sock, uint64_t offset, uint32_t size, uint64_t handle)
+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);
diff --git a/src/types.h b/src/types.h
index 63fe3a6..9f9e744 100644
--- a/src/types.h
+++ b/src/types.h
@@ -37,7 +37,7 @@
#ifdef __GNUC__
#define UNUSED __attribute__ ((unused))
#else
-#define UNUSED dfg dsfg dg
+#error "Please add define for your compiler for UNUSED, or define to nothing for your compiler if not supported"
#endif
#ifdef __linux__
@@ -79,6 +79,9 @@ static const uint16_t dnbd3_packet_magic = (0x73 << 8) | (0x72);
(a).size = net_order_32((a).size); \
} while (0)
#define ENDIAN_MODE "Big Endian"
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN
+#endif
#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)
static const uint16_t dnbd3_packet_magic = (0x73) | (0x72 << 8);
// Make little endian our network byte order as probably 99.999% of machines this will be used on are LE
@@ -88,6 +91,9 @@ static const uint16_t dnbd3_packet_magic = (0x73) | (0x72 << 8);
#define fixup_request(a) while(0)
#define fixup_reply(a) while(0)
#define ENDIAN_MODE "Little Endian"
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN
+#endif
#else
#error "Unknown Endianness"
#endif
@@ -124,17 +130,31 @@ typedef struct
#define CMD_SET_CLIENT_MODE 7
#define CMD_GET_CRC32 8
+#define DNBD3_REQUEST_SIZE 24
#pragma pack(1)
typedef struct
{
- uint16_t magic; // 2byte
- uint16_t cmd; // 2byte
- uint32_t size; // 4byte
- uint64_t offset; // 8byte
- uint64_t handle; // 8byte
+ uint16_t magic; // 2byte
+ uint16_t cmd; // 2byte
+ uint32_t size; // 4byte
+ union {
+ struct {
+#ifdef LITTLE_ENDIAN
+ uint64_t offset_small:56; // 7byte
+ uint8_t hops; // 1byte
+#elif defined(BIG_ENDIAN)
+ uint8_t hops; // 1byte
+ uint64_t offset_small:56; // 7byte
+#endif
+ };
+ uint64_t offset; // 8byte
+ };
+ uint64_t handle; // 8byte
} dnbd3_request_t;
#pragma pack(0)
+_Static_assert( sizeof(dnbd3_request_t) == DNBD3_REQUEST_SIZE, "dnbd3_request_t is messed up" );
+#define DNBD3_REPLY_SIZE 16
#pragma pack(1)
typedef struct
{
@@ -144,6 +164,7 @@ typedef struct
uint64_t handle; // 8byte
} dnbd3_reply_t;
#pragma pack(0)
+_Static_assert( sizeof(dnbd3_reply_t) == DNBD3_REPLY_SIZE, "dnbd3_reply_t is messed up" );
#pragma pack(1)
typedef struct