* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/* For an explanation of the threading model, please main(). */
+
#include <config.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gprintf.h>
+#include <libxml/parser.h>
+
#include <curl/curl.h>
#include "internal.h"
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).
*
DEBUG ("WUI thread starting up");
+ /* This checks wui_gthread global which is actually set in the
+ * main thread. Of course, it might not be set if the WUI thread
+ * runs first. Hence we sleep for the main thread to run. (XXX)
+ */
+ g_usleep (100000);
ASSERT_IS_WUI_THREAD ();
g_async_queue_ref (queue);
static char *
write_fn_finish_capture (void)
{
- char *ret = write_fn_buffer;
+ char *ret;
ASSERT_IS_WUI_THREAD ();
+ /* Make sure the buffer is NUL-terminated before returning it. */
+ write_fn_buffer = g_realloc (write_fn_buffer, write_fn_len+1);
+ write_fn_buffer[write_fn_len] = '\0';
+ ret = write_fn_buffer;
+
write_fn_buffer = NULL;
write_fn_len = -1;
return ret;
CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_FOLLOWLOCATION, (long) 1));
CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_MAXREDIRS, (long) 10));
+ // FIXME when ssl is introduced into ovirt-viewer, remove there two lines
+ CURL_CHECK_ERROR(curl_easy_setopt, (curl, CURLOPT_SSL_VERIFYHOST, 0));
+ CURL_CHECK_ERROR(curl_easy_setopt, (curl, CURLOPT_SSL_VERIFYPEER, 0));
+
/* Try to fetch the URI. */
r = CURL_CHECK_ERROR (curl_easy_perform, (curl));
if (r != CURLE_OK) {
xml = write_fn_finish_capture ();
- /*DEBUG ("XML from /vms =\n%s", xml);*/
parse_vmlist_from_xml (xml);
g_free (xml);
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->mac_addr = vm->mac_addr ? g_strdup (vm->mac_addr) : NULL;
return vm2;
}
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;
+ int len;
+
+ /*DEBUG ("XML =\n%s", xml);*/
+ ASSERT_IS_WUI_THREAD ();
+
+ /* We don't really expect that we won't be able to parse the XML ... */
+ len = strlen (xml);
+ doc = xmlReadMemory (xml, len, NULL, NULL, 0);
+
+ 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 <vms> with a list of <vm> 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 <vm> 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 <vm> 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.forward_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 *) "forward-vnc-port") == 0) {
+ str = xmlNodeGetContent (p);
+ if (str != NULL) {
+ vm.forward_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 <vm> structure");
+ else if (vm.hostid == -1)
+ DEBUG ("required field \"description\" missing from <vm> structure");
+ else if (vm.id == -1)
+ DEBUG ("required field \"description\" missing from <vm> structure");
+ else if (vm.vnc_port == -1)
+ DEBUG ("required field \"vnc-port\" missing from <vm> structure");
+ else if (vm.forward_vnc_port == -1)
+ DEBUG ("required field \"forward-vnc-port\" missing from <vm> structure");
+ else if (vm.uuid == NULL)
+ DEBUG ("required field \"uuid\" missing from <vm> structure");
+ else
+ ret = g_memdup (&vm, sizeof vm);
+ return ret;
}