From 8cb2c797934d717538b3dd585c3759c04131a4ad Mon Sep 17 00:00:00 2001 From: sr Date: Wed, 5 Sep 2012 18:09:28 +0200 Subject: [SERVER] Automatically add and remove alt servers from images depending on wehter the other server is reachable [SERVER] Automatically replicate images from other servers --- src/server/ipc.c | 39 +++++++------ src/server/job.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/server/net.c | 8 ++- src/server/saveload.c | 12 ++-- src/server/xmlutil.c | 8 +-- src/server/xmlutil.h | 4 +- 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 -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 #include -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 -- cgit v1.2.3-55-g7522