From 701e5a967fd6bc97644f39e6fea3714f49a90291 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 6 Sep 2019 17:32:58 +0200 Subject: [SERVER] rpc: Add cachemap feature --- src/server/globals.h | 2 +- src/server/image.c | 16 ++++++++++++++++ src/server/image.h | 2 ++ src/server/rpc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/server/globals.h b/src/server/globals.h index 58b2c9d..df8c595 100644 --- a/src/server/globals.h +++ b/src/server/globals.h @@ -110,7 +110,7 @@ typedef struct typedef struct { ref reference; - atomic_uint_least8_t map[]; + _Atomic uint8_t map[]; } dnbd3_cache_map_t; /** diff --git a/src/server/image.c b/src/server/image.c index 9fcb866..5fa06d8 100644 --- a/src/server/image.c +++ b/src/server/image.c @@ -274,6 +274,22 @@ bool image_ensureOpen(dnbd3_image_t *image) return image->readFd != -1; } +dnbd3_image_t* image_byId(int imgId) +{ + int i; + mutex_lock( &imageListLock ); + for (i = 0; i < _num_images; ++i) { + dnbd3_image_t * const image = _images[i]; + if ( image != NULL && image->id == imgId ) { + image->users++; + mutex_unlock( &imageListLock ); + return image; + } + } + mutex_unlock( &imageListLock ); + return NULL; +} + /** * Get an image by name+rid. This function increases a reference counter, * so you HAVE TO CALL image_release for every image_get() call at some diff --git a/src/server/image.h b/src/server/image.h index cd87f03..449e31f 100644 --- a/src/server/image.h +++ b/src/server/image.h @@ -17,6 +17,8 @@ void image_markComplete(dnbd3_image_t *image); bool image_ensureOpen(dnbd3_image_t *image); +dnbd3_image_t* image_byId(int imgId); + dnbd3_image_t* image_get(char *name, uint16_t revision, bool checkIfWorking); bool image_reopenCacheFd(dnbd3_image_t *image, const bool force); diff --git a/src/server/rpc.c b/src/server/rpc.c index 662263e..548c80f 100644 --- a/src/server/rpc.c +++ b/src/server/rpc.c @@ -9,6 +9,7 @@ #include "fileutil.h" #include "picohttpparser/picohttpparser.h" #include "urldecode.h" +#include "reference.h" #include #include @@ -43,7 +44,9 @@ _Static_assert( sizeof("test") == 5 && sizeof("test2") == 6, "Stringsize messup DEFSTR(STR_CONNECTION, "connection") DEFSTR(STR_CLOSE, "close") DEFSTR(STR_QUERY, "/query") +DEFSTR(STR_CACHEMAP, "/cachemap") DEFSTR(STR_Q, "q") +DEFSTR(STR_ID, "id") static inline bool equals(struct string *s1,struct string *s2) { @@ -81,6 +84,7 @@ static struct { } status; static bool handleStatus(int sock, int permissions, struct field *fields, size_t fields_num, int keepAlive); +static bool handleCacheMap(int sock, int permissions, struct field *fields, size_t fields_num, int keepAlive); static bool sendReply(int sock, const char *status, const char *ctype, const char *payload, ssize_t plen, int keepAlive); static void parsePath(struct string *path, struct string *file, struct field *getv, size_t *getc); static bool hasHeaderValue(struct phr_header *headers, size_t numHeaders, struct string *name, struct string *value); @@ -212,6 +216,8 @@ void rpc_sendStatsJson(int sock, dnbd3_host_t* host, const void* data, const int // Don't care if GET or POST if ( equals( &file, &STR_QUERY ) ) { ok = handleStatus( sock, permissions, getv, getc, keepAlive ); + } else if ( equals( &file, &STR_CACHEMAP ) ) { + ok = handleCacheMap( sock, permissions, getv, getc, keepAlive ); } else { ok = sendReply( sock, "404 Not found", "text/plain", "Nothing", -1, keepAlive ); } @@ -342,6 +348,44 @@ static bool handleStatus(int sock, int permissions, struct field *fields, size_t return ok; } +static bool handleCacheMap(int sock, int permissions, struct field *fields, size_t fields_num, int keepAlive) +{ + if ( !(permissions & ACL_IMAGE_LIST) ) { + return sendReply( sock, "403 Forbidden", "text/plain", "No permission to access image list", -1, keepAlive ); + } + int imgId = -1; + static const char one = 0xff; + for (size_t i = 0; i < fields_num; ++i) { + if ( equals( &fields[i].name, &STR_ID ) ) { + char *broken; + imgId = strtol( fields[i].value.s, &broken, 10 ); + if ( broken != fields[i].value.s ) + break; + imgId = -1; + } + } + if ( imgId == -1 ) + return sendReply( sock, "400 Bad Request", "text/plain", "Missing parameter 'id'", -1, keepAlive ); + dnbd3_image_t *image = image_byId( imgId ); + if ( image == NULL ) + return sendReply( sock, "404 Not found", "text/plain", "Image not found", -1, keepAlive ); + dnbd3_cache_map_t *cache = ref_get_cachemap( image ); + image_release( image ); + int len; + const char *map; + if ( cache == NULL ) { + map = &one; + len = 1; + } else { + _Static_assert( sizeof(const char) == sizeof(_Atomic uint8_t), "Atomic assumption exploded" ); + map = (const char*)cache->map; + len = IMGSIZE_TO_MAPBYTES( image->virtualFilesize ); + } + bool ok = sendReply( sock, "200 OK", "application/octet-stream", map, len, keepAlive ); + ref_put( &cache->reference ); + return ok; +} + static bool sendReply(int sock, const char *status, const char *ctype, const char *payload, ssize_t plen, int keepAlive) { if ( plen == -1 ) plen = strlen( payload ); -- cgit v1.2.3-55-g7522