summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsr2012-09-05 18:09:28 +0200
committersr2012-09-05 18:09:28 +0200
commit8cb2c797934d717538b3dd585c3759c04131a4ad (patch)
treed7d5d2297d0fa2634cdbe510cec474f501b1b486
parent[SERVER] More work towards automatic server discovery and querying (diff)
downloaddnbd3-8cb2c797934d717538b3dd585c3759c04131a4ad.tar.gz
dnbd3-8cb2c797934d717538b3dd585c3759c04131a4ad.tar.xz
dnbd3-8cb2c797934d717538b3dd585c3759c04131a4ad.zip
[SERVER] Automatically add and remove alt servers from images depending on wehter the other server is reachable
[SERVER] Automatically replicate images from other servers
-rw-r--r--src/server/ipc.c39
-rw-r--r--src/server/job.c152
-rw-r--r--src/server/net.c8
-rw-r--r--src/server/saveload.c12
-rw-r--r--src/server/xmlutil.c8
-rw-r--r--src/server/xmlutil.h4
6 files changed, 187 insertions, 36 deletions
diff --git a/src/server/ipc.c b/src/server/ipc.c
index 0dbf46f..c59aa6b 100644
--- a/src/server/ipc.c
+++ b/src/server/ipc.c
@@ -359,7 +359,7 @@ static int ipc_receive(int client_sock)
goto get_info_reply_cleanup;
xmlDocSetRootElement(docReply, root_node);
- xmlNewChild(root_node, NULL, BAD_CAST "namespace", BAD_CAST _local_namespace);
+ xmlNewTextChild(root_node, NULL, BAD_CAST "namespace", BAD_CAST _local_namespace);
// Images
parent_node = xmlNewNode(NULL, BAD_CAST "images");
@@ -379,6 +379,8 @@ static int ipc_receive(int client_sock)
xmlNewProp(tmp_node, BAD_CAST "atime", BAD_CAST strbuffer);
sprintf(strbuffer, "%d", image->rid);
xmlNewProp(tmp_node, BAD_CAST "rid", BAD_CAST strbuffer);
+ sprintf(strbuffer, "%llu", (unsigned long long)image->filesize);
+ xmlNewProp(tmp_node, BAD_CAST "size", BAD_CAST strbuffer);
xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST image->file);
xmlNewProp(tmp_node, BAD_CAST "servers", BAD_CAST "???"); // TODO
if (image->cache_file && image->cache_map)
@@ -643,10 +645,11 @@ void dnbd3_ipc_send(int cmd)
xmlNodePtr cur, childit;
// Print log
- xmlChar *log = getTextFromPath(doc, "/data/log");
+ char *log = getTextFromPath(doc, "/data/log");
if (log)
{
printf("--- Last log lines ----\n%s\n\n", log);
+ xmlFree(log);
}
int watime = 17, wname = 0, wrid = 5;
@@ -655,10 +658,10 @@ void dnbd3_ipc_send(int cmd)
if (cur->type != XML_ELEMENT_NODE)
continue;
NEW_POINTERLIST; // This macro defines an array of pointers
- xmlChar *vid = XML_GETPROP(cur, "name"); // XML_GETPROP is a macro wrapping xmlGetNoNsProp()
- xmlChar *rid = XML_GETPROP(cur, "rid"); // Each of these calls allocates memory for the string
- wname = MAX(wname, xmlStrlen(vid));
- wrid = MAX(wrid, xmlStrlen(rid));
+ char *vid = XML_GETPROP(cur, "name"); // XML_GETPROP is a macro wrapping xmlGetNoNsProp()
+ char *rid = XML_GETPROP(cur, "rid"); // Each of these calls allocates memory for the string
+ wname = MAX(wname, strlen(vid));
+ wrid = MAX(wrid, strlen(rid));
FREE_POINTERLIST; // This macro simply frees all pointers in the above array
} END_FOR_EACH;
@@ -677,11 +680,11 @@ void dnbd3_ipc_send(int cmd)
continue;
NEW_POINTERLIST;
++count;
- xmlChar *numatime = XML_GETPROP(cur, "atime");
- xmlChar *vid = XML_GETPROP(cur, "name");
- xmlChar *rid = XML_GETPROP(cur, "rid");
- xmlChar *file = XML_GETPROP(cur, "file");
- time_t at = (time_t)atol((char*)numatime);
+ char *numatime = XML_GETPROP(cur, "atime");
+ char *vid = XML_GETPROP(cur, "name");
+ char *rid = XML_GETPROP(cur, "rid");
+ char *file = XML_GETPROP(cur, "file");
+ time_t at = (time_t)atol(numatime);
struct tm *timeinfo = localtime(&at);
strftime(strbuffer, STRBUFLEN, "%d.%m.%y %H:%M:%S", timeinfo);
printf(format, strbuffer, vid, rid, file);
@@ -717,8 +720,8 @@ void dnbd3_ipc_send(int cmd)
continue;
NEW_POINTERLIST;
++count;
- xmlChar *ip = XML_GETPROP(cur, "ip");
- xmlChar *comment = XML_GETPROP(cur, "comment");
+ char *ip = XML_GETPROP(cur, "ip");
+ char *comment = XML_GETPROP(cur, "comment");
if (comment)
printf("%-30s (%s)\n", ip, comment);
else
@@ -728,9 +731,9 @@ void dnbd3_ipc_send(int cmd)
if (childit->type != XML_ELEMENT_NODE || childit->name == NULL || strcmp((const char*)childit->name, "namespace") != 0)
continue;
NEW_POINTERLIST;
- xmlChar *name = XML_GETPROP(childit, "name");
- xmlChar *replicate = XML_GETPROP(childit, "replicate");
- xmlChar *recursive = XML_GETPROP(childit, "recursive");
+ char *name = XML_GETPROP(childit, "name");
+ char *replicate = XML_GETPROP(childit, "replicate");
+ char *recursive = XML_GETPROP(childit, "recursive");
printf(" %-40s ", name);
if (replicate && *replicate != '0')
printf(" replicate");
@@ -772,10 +775,10 @@ static int is_password_correct(xmlDocPtr doc)
memlogf("[WARNING] IPC access granted as no password is set!");
return 1;
}
- xmlChar *pass = getTextFromPath(doc, "/data/password");
+ char *pass = getTextFromPath(doc, "/data/password");
if (pass == NULL)
return 0;
- if (strcmp((char *)pass, _ipc_password) == 0)
+ if (strcmp(pass, _ipc_password) == 0)
{
xmlFree(pass);
return 1;
diff --git a/src/server/job.c b/src/server/job.c
index cf45681..6386423 100644
--- a/src/server/job.c
+++ b/src/server/job.c
@@ -46,7 +46,8 @@ static char keep_running = TRUE;
// Private functions
static char *get_free_device();
static void query_servers();
-static void dnbd3_remove_alt_server(dnbd3_trusted_server_t *server);
+static void add_alt_server(dnbd3_image_t *image, dnbd3_host_t *host);
+static void remove_alt_server(dnbd3_trusted_server_t *server);
static void update_image_atimes(time_t now);
//
@@ -217,14 +218,105 @@ static void query_servers()
//
// Process data, update server info, add/remove this server as alt server for images, replicate images, etc.
xmlDocPtr doc = xmlReadMemory(xmlbuffer, header.size, "noname.xml", NULL, 0);
- free(xmlbuffer);
- xmlbuffer = NULL;
+
if (doc == NULL)
{
memlogf("[WARNING] Could not parse XML data received by other server.");
goto communication_error;
}
// Data seems ok
+ char *ns = getTextFromPath(doc, "/data/namespace");
+ if (ns && *ns == '\0')
+ {
+ xmlFree(ns);
+ ns = NULL;
+ }
+ else
+ {
+ printf("[DEBUG] Other server's default namespace is '%s'\n", ns);
+ if (!is_valid_namespace(ns))
+ {
+ printf("[DEBUG] Ignoring invalid namespace from other server.\n");
+ xmlFree(ns);
+ ns = NULL;
+ }
+ }
+
+ xmlNodePtr cur;
+ FOR_EACH_NODE(doc, "/data/images/image", cur)
+ {
+ if (cur->type != XML_ELEMENT_NODE)
+ continue;
+ NEW_POINTERLIST;
+ char *image = XML_GETPROP(cur, "name");
+ char *ridstr = XML_GETPROP(cur, "rid");
+ if (!image || !ridstr)
+ goto free_current_image;
+ int rid = atoi(ridstr);
+ if (rid <= 0)
+ {
+ printf("[DEBUG] Ignoring remote image with rid %d\n", rid);
+ goto free_current_image;
+ }
+ char *slash = strrchr(image, '/');
+ if (slash == NULL)
+ {
+ if (!ns)
+ goto free_current_image;
+ if (!is_valid_imagename(image))
+ {
+ printf("[DEBUG] Invalid image name: '%s'\n", image);
+ goto free_current_image;
+ }
+ snprintf(xmlbuffer, MAX_IPC_PAYLOAD, "%s/%s", ns, image);
+ }
+ else
+ {
+ *slash++ = '\0';
+ if (!is_valid_namespace(image))
+ {
+ printf("[DEBUG] Ignoring remote image with invalid namespace '%s'\n", image);
+ goto free_current_image;
+ }
+ if (!is_valid_imagename(slash))
+ {
+ printf("[DEBUG] Ignoring remote image with invalid name '%s'\n", slash);
+ goto free_current_image;
+ }
+ snprintf(xmlbuffer, MAX_IPC_PAYLOAD, "%s/%s", image, slash);
+ }
+ // Image seems legit, check if there's a local copy
+ pthread_spin_lock(&_spinlock);
+ dnbd3_image_t *local_image = dnbd3_get_image(xmlbuffer, rid, FALSE);
+ if (local_image == NULL)
+ {
+ pthread_spin_unlock(&_spinlock);
+ // Image is NEW, add it!
+ // TODO: Check if replication is requested for this namespace
+ dnbd3_image_t newimage;
+ memset(&newimage, 0, sizeof(newimage));
+ newimage.config_group = xmlbuffer;
+ newimage.rid = rid;
+ dnbd3_add_image(&newimage);
+ pthread_spin_lock(&_spinlock);
+ local_image = dnbd3_get_image(xmlbuffer, rid, FALSE);
+ if (local_image)
+ add_alt_server(local_image, &server->host);
+ pthread_spin_unlock(&_spinlock);
+ }
+ else
+ {
+ // Image is already KNOWN, add alt server if appropriate
+ // TODO: Check if requested for namespace
+ add_alt_server(local_image, &server->host);
+ pthread_spin_unlock(&_spinlock);
+ }
+ // Cleanup
+free_current_image:
+ FREE_POINTERLIST;
+ } END_FOR_EACH;
+
+
// ...
xmlFreeDoc(doc);
//
@@ -236,7 +328,7 @@ communication_error:
if (g_slist_find(_trusted_servers, server))
{
if (server->unreachable < 10 && ++server->unreachable == 5)
- dnbd3_remove_alt_server(server);
+ remove_alt_server(server);
}
pthread_spin_unlock(&_spinlock);
}
@@ -245,7 +337,57 @@ communication_error:
/**
* !! Call this while holding the lock !!
*/
-static void dnbd3_remove_alt_server(dnbd3_trusted_server_t *server)
+static void add_alt_server(dnbd3_image_t *image, dnbd3_host_t *host)
+{
+ int i;
+ for (i = 0; i < NUMBER_SERVERS; ++i)
+ {
+ if (is_same_server(host, &image->servers[i].host))
+ { // Alt server already known for this image
+ if (image->servers[i].failures)
+ { // It was disabled, re-enable and send info to clients
+ image->servers[i].failures = 0;
+ break;
+ }
+ else // Alt-Server already known and active, do nothing
+ return;
+ }
+ }
+ // Add to list if it wasn't in there
+ if (i >= NUMBER_SERVERS)
+ for (i = 0; i < NUMBER_SERVERS; ++i)
+ {
+ if (image->servers[i].host.type == 0)
+ {
+ image->servers[i].host = *host;
+ break;
+ }
+ }
+ // Broadcast to connected clients
+ GSList *itc;
+ dnbd3_reply_t header;
+ header.cmd = CMD_GET_SERVERS;
+ header.magic = dnbd3_packet_magic;
+ header.size = sizeof(dnbd3_server_entry_t);
+ fixup_reply(header);
+ for (itc = _dnbd3_clients; itc; itc = itc->next)
+ {
+ dnbd3_client_t *const client = itc->data;
+ if (client->image == image)
+ {
+ // Don't send message directly as the lock is being held; instead, enqueue it
+ NEW_BINSTRING(message, sizeof(header) + sizeof(*host));
+ memcpy(message->data, &header, sizeof(header));
+ memcpy(message->data + sizeof(header), host, sizeof(*host));
+ client->sendqueue = g_slist_append(client->sendqueue, message);
+ }
+ }
+}
+
+/**
+ * !! Call this while holding the lock !!
+ */
+static void remove_alt_server(dnbd3_trusted_server_t *server)
{
GSList *iti, *itc;
int i;
diff --git a/src/server/net.c b/src/server/net.c
index b351ed3..7456ebd 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -180,12 +180,16 @@ void *dnbd3_handle_query(void *dnbd3_client)
const time_t now = time(NULL);
if (!image)
{
- printf("[DEBUG] Client requested non-existent image '%s' (rid:%d)\n", image_name, (int)rid);
+ printf("[DEBUG] Client requested non-existent image '%s' (rid:%d), rejected\n", image_name, (int)rid);
+ }
+ else if (!image->working)
+ {
+ printf("[DEBUG] Client requested non-working image '%s' (rid:%d), rejected\n", image_name, (int)rid);
}
else if ((image->delete_soft != 0 && image->delete_soft < now)
|| (image->delete_hard != 0 && image->delete_hard < now))
{
- printf("[DEBUG] Client requested end-of-life image '%s' (rid:%d)\n", image_name, (int)rid);
+ printf("[DEBUG] Client requested end-of-life image '%s' (rid:%d), rejected\n", image_name, (int)rid);
}
else
{
diff --git a/src/server/saveload.c b/src/server/saveload.c
index b9c0164..365934b 100644
--- a/src/server/saveload.c
+++ b/src/server/saveload.c
@@ -152,9 +152,11 @@ int dnbd3_add_image(dnbd3_image_t *image)
}
dnbd3_image_t *newimage = prepare_image(image->config_group, image->rid, image->file, image->cache_file);
+ image = NULL;
if (newimage)
{
- _dnbd3_images = g_slist_prepend(_dnbd3_images, image);
+ memlogf("[INFO] Added image '%s'", newimage->low_name);
+ _dnbd3_images = g_slist_prepend(_dnbd3_images, newimage);
}
else
{
@@ -163,10 +165,10 @@ int dnbd3_add_image(dnbd3_image_t *image)
}
// Adding image was successful, write config file
- g_key_file_set_integer(_config_handle, image->config_group, "rid", image->rid);
- g_key_file_set_string(_config_handle, image->config_group, "file", image->file);
+ g_key_file_set_integer(_config_handle, newimage->config_group, "rid", newimage->rid);
+ g_key_file_set_string(_config_handle, newimage->config_group, "file", newimage->file);
//g_key_file_set_string(_config_handle, image->name, "servers", image->serverss); // TODO: Save servers as string
- g_key_file_set_string(_config_handle, image->config_group, "cache", image->cache_file);
+ g_key_file_set_string(_config_handle, newimage->config_group, "cache", newimage->cache_file);
pthread_spin_unlock(&_spinlock);
@@ -308,7 +310,7 @@ static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file,
return NULL;
}
- if (strchr(image_name, '.') == NULL && _local_namespace == NULL)
+ if (strchr(image_name, '/') == NULL && _local_namespace == NULL)
{
memlogf("[ERROR] Image '%s' has local name and no default namespace is defined; entry ignored.", image_name);
return NULL;
diff --git a/src/server/xmlutil.c b/src/server/xmlutil.c
index 62736cd..1718bfb 100644
--- a/src/server/xmlutil.c
+++ b/src/server/xmlutil.c
@@ -3,7 +3,7 @@
#include <libxml/xpath.h>
-xmlChar *getTextFromPath(xmlDocPtr doc, char *xpath)
+char *getTextFromPath(xmlDocPtr doc, char *xpath)
{
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
if (xpathCtx == NULL)
@@ -14,12 +14,12 @@ xmlChar *getTextFromPath(xmlDocPtr doc, char *xpath)
xmlXPathFreeContext(xpathCtx);
return NULL;
}
- xmlChar *retval = NULL;
+ char *retval = NULL;
if (xpathObj->stringval)
- retval = xmlStrdup(xpathObj->stringval);
+ retval = (char*)xmlStrdup(xpathObj->stringval);
else if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 && xpathObj->nodesetval->nodeTab && xpathObj->nodesetval->nodeTab[0])
{
- retval = xmlNodeGetContent(xpathObj->nodesetval->nodeTab[0]);
+ retval = (char*)xmlNodeGetContent(xpathObj->nodesetval->nodeTab[0]);
}
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
diff --git a/src/server/xmlutil.h b/src/server/xmlutil.h
index 971d8a9..fddb317 100644
--- a/src/server/xmlutil.h
+++ b/src/server/xmlutil.h
@@ -4,7 +4,7 @@
#include <libxml/xmlstring.h>
#include <libxml/tree.h>
-xmlChar *getTextFromPath(xmlDocPtr doc, char *xpath);
+char *getTextFromPath(xmlDocPtr doc, char *xpath);
#define FOR_EACH_NODE(_doc, _path, _node) do { \
xmlXPathContextPtr _makro_xpathCtx = xmlXPathNewContext(_doc); \
@@ -33,6 +33,6 @@ xmlChar *getTextFromPath(xmlDocPtr doc, char *xpath);
xmlFree(_makro_ptrlist[_makro_i_]); \
} } while(0)
-#define XML_GETPROP(_node, _name) (xmlChar*)(_makro_ptrlist[(_makro_usedcount >= NUM_POINTERS_IN_LIST ? 0 : _makro_usedcount++)] = xmlGetNoNsProp(_node, BAD_CAST _name))
+#define XML_GETPROP(_node, _name) (char*)(_makro_ptrlist[(_makro_usedcount >= NUM_POINTERS_IN_LIST ? 0 : _makro_usedcount++)] = xmlGetNoNsProp(_node, BAD_CAST _name))
#endif