From: Richard Jones Date: Sat, 29 Nov 2008 14:50:48 +0000 (+0000) Subject: Parse structures. X-Git-Url: http://git.annexia.org/?a=commitdiff_plain;h=432ef642869fbbac2d6f6d111d80137cc5e7b119;p=ovirt-viewer.git Parse structures. --- diff --git a/internal.h b/internal.h index 77b3907..8f5ec01 100644 --- a/internal.h +++ b/internal.h @@ -103,13 +103,18 @@ struct vm { char *description; int hostid; int id; + int vnc_port; + + /* Only description, hostid, id and vnc_port fields are required. + * The remainder may be NULL / -1 to indicate they were missing in + * the data we got back from the WUI. + */ long mem_allocated; /* Kbytes */ long mem_used; /* Kbytes */ int vcpus_allocated; int vcpus_used; char *state; char *uuid; /* Printable UUID. */ - int vnc_port; char *mac_addr; /* Printable MAC addr. */ }; @@ -169,4 +174,7 @@ extern gboolean main_login_error (gpointer str); /* The WUI thread reports a general status error. */ extern gboolean main_status_error (gpointer str); +/* The WUI thread has updated the vm list. */ +extern gboolean main_vmlist_updated (gpointer); + #endif /* OVIRT_VIEWER_INTERNAL_H */ diff --git a/main.c b/main.c index 0425128..b4a3607 100644 --- a/main.c +++ b/main.c @@ -550,3 +550,13 @@ main_status_error (gpointer _str) return FALSE; } + +/* The WUI thread has updated the vm list. */ +gboolean +main_vmlist_updated (gpointer data) +{ + DEBUG ("vmlist updated"); + ASSERT_IS_MAIN_THREAD (); + + return FALSE; +} diff --git a/wui_thread.c b/wui_thread.c index 94631b6..8fbd930 100644 --- a/wui_thread.c +++ b/wui_thread.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include "internal.h" @@ -42,6 +44,7 @@ static gboolean do_connect (void); static gboolean do_login (void); static gboolean refresh_vm_list (void); static void parse_vmlist_from_xml (const char *xml); +static struct vm *parse_vm_from_xml (xmlNodePtr node); /* Messages (main thread -> WUI thread only). * @@ -752,7 +755,6 @@ refresh_vm_list (void) xml = write_fn_finish_capture (); - /*DEBUG ("XML from /vms =\n%s", xml);*/ parse_vmlist_from_xml (xml); g_free (xml); @@ -791,9 +793,9 @@ copy_vm (struct vm *vm) vm2 = g_memdup (vm, sizeof (*vm)); vm2->description = g_strdup (vm->description); - vm2->state = g_strdup (vm->state); - vm2->uuid = g_strdup (vm->uuid); - vm2->mac_addr = g_strdup (vm->mac_addr); + vm2->state = vm->state ? g_strdup (vm->state) : NULL; + vm2->uuid = vm->uuid ? g_strdup (vm->uuid) : NULL; + vm2->mac_addr = vm->mac_addr ? g_strdup (vm->mac_addr) : NULL; return vm2; } @@ -865,11 +867,198 @@ wui_thread_get_vmlist (GSList **ret) static void parse_vmlist_from_xml (const char *xml) { - + xmlDocPtr doc = NULL; + xmlNodePtr root; + xmlNodePtr node; + char *error_str; + GSList *new_vmlist = NULL; + struct vm *vm; + + /*DEBUG ("XML =\n%s", xml);*/ + ASSERT_IS_WUI_THREAD (); + + /* We don't really expect that we won't be able to parse the XML ... */ + doc = xmlParseDoc ((const xmlChar *) xml); + if (!doc) { + DEBUG ("error parsing XML document, xml =\n%s", xml); + error_str = g_strdup ("error parsing XML document from remote server"); + g_idle_add (main_status_error, error_str); + goto done; + } + + root = xmlDocGetRootElement (doc); + if (!root) { + DEBUG ("XML document was empty"); + error_str = g_strdup ("XML document was empty"); + g_idle_add (main_status_error, error_str); + goto done; + } + + /* We expect the root element will be either "nil-classes" + * or "vms", with the former indicating an empty list of VMs. + */ + if (xmlStrcmp (root->name, (const xmlChar *) "nil-classes") == 0) { + g_static_mutex_lock (&vmlist_mutex); + vmlist_valid = TRUE; + free_vmlist (vmlist); + vmlist = NULL; + g_static_mutex_unlock (&vmlist_mutex); + + /* Signal to the main UI thread that the list has been updated. */ + g_idle_add (main_vmlist_updated, NULL); + + goto done; + } + if (xmlStrcmp (root->name, (const xmlChar *) "vms") != 0) { + DEBUG ("unexpected root node in XML document, xml =\n%s", xml); + error_str = g_strdup ("unexpected root node in XML document"); + g_idle_add (main_status_error, error_str); + goto done; + } + /* The document is with a list of elements which + * we process in turn. + */ + for (node = root->xmlChildrenNode; node != NULL; node = node->next) { + if (xmlStrcmp (node->name, (const xmlChar *) "vm") == 0) { + vm = parse_vm_from_xml (node); + if (!vm) { + error_str = g_strdup ("could not parse element"); + g_idle_add (main_status_error, error_str); + + free_vmlist (new_vmlist); + goto done; + } + new_vmlist = g_slist_prepend (new_vmlist, vm); + } + } + /* Successfully parsed all the nodes, so swap the old and new + * vmlists. + */ + g_static_mutex_lock (&vmlist_mutex); + vmlist_valid = TRUE; + free_vmlist (vmlist); + vmlist = new_vmlist; + g_static_mutex_unlock (&vmlist_mutex); + + /* Signal that the vmlist has been updated. */ + g_idle_add (main_vmlist_updated, NULL); + + done: + /* Free up XML resources used before returning. */ + if (doc) xmlFreeDoc (doc); +} +static struct vm * +parse_vm_from_xml (xmlNodePtr node) +{ + xmlNodePtr p; + struct vm vm, *ret; + xmlChar *str; + + memset (&vm, 0, sizeof vm); + vm.hostid = -1; + vm.id = -1; + vm.vnc_port = -1; + vm.mem_allocated = -1; + vm.mem_used = -1; + vm.vcpus_allocated = -1; + vm.vcpus_used = -1; + + for (p = node->xmlChildrenNode; p != NULL; p = p->next) { + if (xmlStrcmp (p->name, (const xmlChar *) "description") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.description = g_strdup ((char *) str); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "host-id") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.hostid = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "id") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.id = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "memory-allocated") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.mem_allocated = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "memory-used") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.mem_used = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "num-vcpus-allocated") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.vcpus_allocated = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "num-vcpus-used") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.vcpus_used = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "state") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.state = g_strdup ((char *) str); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "uuid") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.uuid = g_strdup ((char *) str); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "vnc-port") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.vnc_port = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } + else if (xmlStrcmp (p->name, (const xmlChar *) "vnic-mac-addr") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.mac_addr = g_strdup ((char *) str); + xmlFree (str); + } + } + } + /* Make sure we've got the required fields. */ + ret = NULL; + if (vm.description == NULL) + DEBUG ("required field \"description\" missing from structure"); + else if (vm.hostid == -1) + DEBUG ("required field \"description\" missing from structure"); + else if (vm.id == -1) + DEBUG ("required field \"description\" missing from structure"); + else if (vm.vnc_port == -1) + DEBUG ("required field \"vnc-port\" missing from structure"); + else + ret = g_memdup (&vm, sizeof vm); + return ret; }