1 /* ovirt viewer console application
2 * Copyright (C) 2008 Red Hat Inc.
3 * Written by Richard W.M. Jones <rjones@redhat.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <glib/gprintf.h>
30 #include <libxml/parser.h>
32 #include <curl/curl.h>
36 /* Private functions. */
37 static gpointer wui_thread (gpointer data);
38 static void wui_thread_send_quit (void);
39 static void do_curl_init (void);
40 static void write_fn_start_capture (void);
41 static char *write_fn_finish_capture (void);
42 static void write_fn_discard_capture_buffer (void);
43 static gboolean do_connect (void);
44 static gboolean do_login (void);
45 static gboolean refresh_vm_list (void);
46 static void parse_vmlist_from_xml (const char *xml);
47 static struct vm *parse_vm_from_xml (xmlNodePtr node);
49 /* Messages (main thread -> WUI thread only).
51 * These are passed by reference. They are allocated by the sender
52 * (ie. the main thread) and freed by the receiver (ie. the WUI thread).
55 QUIT, /* Tell the WUI thread to quit cleanly. */
56 CONNECT, /* Tell to connect (just fetch the URI). */
57 DISCONNECT, /* Tell to disconnect, forget state. */
58 LOGIN, /* Tell to login, and pass credentials. */
59 REFRESH_VM_LIST, /* Tell to refresh the VM list right away. */
63 enum message_type type;
68 /* Start the WUI thread. See main() for explanation of the threading model. */
69 static GThread *wui_gthread = NULL;
70 static GThread *main_gthread = NULL;
71 static GAsyncQueue *wui_thread_queue = NULL;
74 start_wui_thread (void)
78 DEBUG ("starting the WUI thread");
80 assert (wui_gthread == NULL);
82 main_gthread = g_thread_self ();
84 /* Create the message queue for main -> WUI thread communications. */
85 wui_thread_queue = g_async_queue_new ();
87 wui_gthread = g_thread_create (wui_thread, wui_thread_queue, TRUE, &error);
89 g_print ("%s\n", error->message);
96 stop_wui_thread (void)
98 DEBUG ("stopping the WUI thread");
100 assert (wui_gthread != NULL);
101 ASSERT_IS_MAIN_THREAD ();
103 /* Send a quit message then wait for the WUI thread to join.
105 * This "nice" shutdown could cause the UI to hang for an
106 * indefinite period (eg. if the WUI thread is engaged in some
107 * long connection or download from the remote server). But
108 * I want to keep it this way for the moment so that we can
109 * diagnose problems with the WUI thread.
111 * (This could be solved with some sort of interruptible
112 * join, but glib doesn't support that AFAICT).
114 wui_thread_send_quit ();
115 (void) g_thread_join (wui_gthread);
116 g_async_queue_unref (wui_thread_queue);
121 assert_is_wui_thread (const char *filename, int lineno)
123 if (g_thread_self () != wui_gthread) {
124 fprintf (stderr, "%s:%d: internal error: this function should only run in the context of the WUI thread\n", filename, lineno);
130 assert_is_main_thread (const char *filename, int lineno)
132 if (g_thread_self () != main_gthread) {
133 fprintf (stderr, "%s:%d: internal error: this function should only run in the context of the main thread\n", filename, lineno);
138 /* Send the quit message to the WUI thread. */
140 wui_thread_send_quit (void)
144 ASSERT_IS_MAIN_THREAD ();
146 msg = g_new (struct message, 1);
148 g_async_queue_push (wui_thread_queue, msg);
151 /* Send the connect message to the WUI thread. */
153 wui_thread_send_connect (const char *uri)
157 ASSERT_IS_MAIN_THREAD ();
159 msg = g_new (struct message, 1);
161 msg->str1 = g_strdup (uri);
162 g_async_queue_push (wui_thread_queue, msg);
165 /* Send the disconnect message to the WUI thread. */
167 wui_thread_send_disconnect (void)
171 ASSERT_IS_MAIN_THREAD ();
173 msg = g_new (struct message, 1);
174 msg->type = DISCONNECT;
175 g_async_queue_push (wui_thread_queue, msg);
178 /* Send the login message to the WUI thread. */
180 wui_thread_send_login (const char *username, const char *password)
184 ASSERT_IS_MAIN_THREAD ();
186 msg = g_new (struct message, 1);
188 msg->str1 = g_strdup (username);
189 msg->str2 = g_strdup (password);
190 g_async_queue_push (wui_thread_queue, msg);
193 /* Send the refresh VM list message to the WUI thread. */
195 wui_thread_send_refresh_vm_list (void)
199 ASSERT_IS_MAIN_THREAD ();
201 msg = g_new (struct message, 1);
202 msg->type = REFRESH_VM_LIST;
203 g_async_queue_push (wui_thread_queue, msg);
206 /* The current state.
208 * For safety, the main thread must lock this before reading, and the
209 * WUI thread must lock this before writing. However the WUI thread
210 * does not need to lock before reading, because no other thread
213 static gboolean connected = FALSE;
214 static gboolean logged_in = FALSE;
215 static gboolean busy = FALSE;
216 static GStaticMutex state_mutex;
218 static void set_connected (gboolean);
219 static void set_logged_in (gboolean);
220 static void set_busy (gboolean);
222 /* The private state of the WUI thread. */
223 static int secs_between_refresh = 60;
224 static CURL *curl = NULL;
225 static char curl_error_buffer[CURL_ERROR_SIZE];
226 static char *uri = NULL;
227 static char *username = NULL;
228 static char *password = NULL;
230 static gboolean process_message (struct message *);
232 /* The WUI thread. See main() above for explanation of
233 * the threading model.
236 wui_thread (gpointer _queue)
238 GAsyncQueue *queue = (GAsyncQueue *) _queue;
239 gboolean quit = FALSE;
244 DEBUG ("WUI thread starting up");
246 ASSERT_IS_WUI_THREAD ();
248 g_async_queue_ref (queue);
250 /* In the thread's loop we check for new instructions from the main
251 * thread and carry them out. Also, if we are connected and logged
252 * in then we periodically recheck the list of VMs.
258 g_get_current_time (&tv);
259 g_time_val_add (&tv, secs_between_refresh * 1000000);
260 _msg = g_async_queue_timed_pop (queue, &tv);
262 _msg = g_async_queue_pop (queue);
266 msg = (struct message *) _msg;
269 DEBUG ("received message with msg->type = %d", msg->type);
270 quit = process_message (msg);
271 /* Don't free any strings in the message - we've saved them. */
274 /* No message, must have got a timeout instead, which means
275 * we are logged in and we should refresh the list of VMs.
276 * Note it's not an error if we temporarily lose contact
283 DEBUG ("WUI thread shutting down cleanly");
285 g_async_queue_unref (queue);
286 g_thread_exit (NULL);
287 return NULL; /* not reached? */
290 /* The WUI thread calls this to safely update the state variables.
291 * This also updates elements in the UI by setting idle callbacks
292 * which are executed in the context of the main thread.
295 set_connected (gboolean new_connected)
297 ASSERT_IS_WUI_THREAD ();
299 g_static_mutex_lock (&state_mutex);
300 connected = new_connected;
301 g_static_mutex_unlock (&state_mutex);
304 g_idle_add (main_connected, NULL);
306 g_idle_add (main_disconnected, NULL);
310 set_logged_in (gboolean new_logged_in)
312 ASSERT_IS_WUI_THREAD ();
314 g_static_mutex_lock (&state_mutex);
315 logged_in = new_logged_in;
316 g_static_mutex_unlock (&state_mutex);
319 g_idle_add (main_logged_in, NULL);
321 g_idle_add (main_logged_out, NULL);
325 set_busy (gboolean new_busy)
327 ASSERT_IS_WUI_THREAD ();
329 g_static_mutex_lock (&state_mutex);
331 g_static_mutex_unlock (&state_mutex);
334 g_idle_add (main_busy, NULL);
336 g_idle_add (main_idle, NULL);
339 /* The main thread should call these functions to get the WUI thread's
343 wui_thread_is_connected (void)
347 ASSERT_IS_MAIN_THREAD ();
349 g_static_mutex_lock (&state_mutex);
351 g_static_mutex_unlock (&state_mutex);
356 wui_thread_is_logged_in (void)
360 ASSERT_IS_MAIN_THREAD ();
362 g_static_mutex_lock (&state_mutex);
364 g_static_mutex_unlock (&state_mutex);
369 wui_thread_is_busy (void)
373 ASSERT_IS_MAIN_THREAD ();
375 g_static_mutex_lock (&state_mutex);
377 g_static_mutex_unlock (&state_mutex);
381 /* Process a message from the main thread. */
383 process_message (struct message *msg)
385 ASSERT_IS_WUI_THREAD ();
389 write_fn_discard_capture_buffer ();
390 if (curl) curl_easy_cleanup (curl);
391 if (uri) g_free (uri);
392 if (username) g_free (username);
393 if (password) g_free (password);
394 set_connected (FALSE);
395 set_logged_in (FALSE);
399 write_fn_discard_capture_buffer ();
400 if (curl) curl_easy_cleanup (curl);
402 if (uri) g_free (uri);
406 set_connected (TRUE);
408 set_connected (FALSE);
409 set_logged_in (FALSE);
414 /* This just forgets the state. REST is connectionless. */
415 write_fn_discard_capture_buffer ();
416 if (curl) curl_easy_cleanup (curl);
418 if (uri) g_free (uri);
420 if (username) g_free (username);
422 if (password) g_free (password);
424 set_connected (FALSE);
425 set_logged_in (FALSE);
429 if (username) g_free (username);
430 username = msg->str1;
431 if (password) g_free (password);
432 password = msg->str2;
434 /* If we're not connected, this message just updates the
435 * username and password. Otherwise if we are connected,
436 * try to login and grab the initial list of VMs.
440 set_logged_in (TRUE);
441 if (refresh_vm_list ())
442 secs_between_refresh = 60;
444 set_logged_in (FALSE);
449 case REFRESH_VM_LIST:
450 if (connected && logged_in) {
452 secs_between_refresh = 60;
457 DEBUG ("unknown message type %d", msg->type);
464 /* Macro for easy handling of CURL errors. */
465 #define CURL_CHECK_ERROR(fn, args) \
467 CURLcode __r = fn args; \
468 if (__r != CURLE_OK) { \
469 fprintf (stderr, "%s: %s\n", #fn, curl_easy_strerror (__r)); \
474 /* Libcurl has a really crufty method for handling HTTP headers and
475 * data. We set these functions as callbacks, because the default
476 * callback functions print the data out to stderr. In order to
477 * capture the data, we have to keep state here.
480 static char *write_fn_buffer = NULL;
481 static ssize_t write_fn_len = -1;
484 write_fn (void *ptr, size_t size, size_t nmemb, void *stream)
486 int bytes = size * nmemb;
489 ASSERT_IS_WUI_THREAD ();
491 if (write_fn_len >= 0) { /* We're capturing. */
492 old_start = write_fn_len;
493 write_fn_len += bytes;
494 write_fn_buffer = g_realloc (write_fn_buffer, write_fn_len);
495 memcpy (write_fn_buffer + old_start, ptr, bytes);
501 /* Start capturing HTTP response data. */
503 write_fn_start_capture (void)
505 ASSERT_IS_WUI_THREAD ();
507 write_fn_discard_capture_buffer ();
508 write_fn_buffer = NULL;
512 /* Finish capture and return the capture buffer. Caller must free. */
514 write_fn_finish_capture (void)
516 char *ret = write_fn_buffer;
518 ASSERT_IS_WUI_THREAD ();
520 write_fn_buffer = NULL;
525 /* Stop capturing and discard the capture buffer, if any. */
527 write_fn_discard_capture_buffer (void)
529 ASSERT_IS_WUI_THREAD ();
531 g_free (write_fn_buffer);
532 write_fn_buffer = NULL;
537 header_fn (void *ptr, size_t size, size_t nmemb, void *stream)
539 int bytes = size * nmemb;
541 ASSERT_IS_WUI_THREAD ();
546 /* Called from the message loop to initialize the CURL handle. */
550 DEBUG ("initializing libcurl");
552 ASSERT_IS_WUI_THREAD ();
554 curl = curl_easy_init ();
555 if (!curl) { /* This is probably quite bad, so abort. */
556 DEBUG ("curl_easy_init failed");
560 CURL_CHECK_ERROR (curl_easy_setopt,
561 (curl, CURLOPT_CAINFO, cainfo));
562 CURL_CHECK_ERROR (curl_easy_setopt,
563 (curl, CURLOPT_SSL_VERIFYHOST, check_cert ? 2 : 0));
564 CURL_CHECK_ERROR (curl_easy_setopt,
565 (curl, CURLOPT_SSL_VERIFYPEER, check_cert ? 1 : 0));
567 CURL_CHECK_ERROR (curl_easy_setopt,
568 (curl, CURLOPT_WRITEFUNCTION, write_fn));
569 CURL_CHECK_ERROR (curl_easy_setopt,
570 (curl, CURLOPT_HEADERFUNCTION, header_fn));
572 /* This enables error messages in curl_easy_perform. */
573 CURL_CHECK_ERROR (curl_easy_setopt,
574 (curl, CURLOPT_ERRORBUFFER, curl_error_buffer));
576 /* This enables cookie handling, using an internal cookiejar. */
577 CURL_CHECK_ERROR (curl_easy_setopt,
578 (curl, CURLOPT_COOKIEFILE, ""));
581 /* Called from the message loop. Try to connect to the current URI.
582 * Returns true on success.
591 DEBUG ("connecting to uri %s", uri);
592 ASSERT_IS_WUI_THREAD ();
594 /* Set the URI for libcurl. */
595 CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_URL, uri));
597 /* Try to fetch the URI. */
598 r = CURL_CHECK_ERROR (curl_easy_perform, (curl));
600 /* Signal an error back to the main thread. */
601 error_str = g_strdup (curl_easy_strerror (r));
602 g_idle_add (main_connection_error, error_str);
606 CURL_CHECK_ERROR (curl_easy_getinfo, (curl, CURLINFO_RESPONSE_CODE, &code));
607 DEBUG ("HTTP return code is %ld", code);
608 if (code != 200 && code != 302 && code != 401) {
609 /* XXX If only glib had g_asprintf. */
610 error_str = g_strdup ("unexpected HTTP return code from server");
611 g_idle_add (main_connection_error, error_str);
618 /* Called from the message loop. Try to login to 'URI/login' with the
619 * current username and password. Returns true on success.
631 DEBUG ("logging in with username %s, password *****", username);
632 ASSERT_IS_WUI_THREAD ();
634 /* Generate the login URI from the base URI. */
635 len = strlen (uri) + 6 + 1;
636 login_uri = g_alloca (len);
637 snprintf (login_uri, len, "%s/login", uri);
639 DEBUG ("login URI %s", login_uri);
641 /* Set the URI for libcurl. */
642 CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_URL, login_uri));
644 /* Construct the username:password for CURL. */
645 len = strlen (username) + strlen (password) + 2;
646 userpwd = g_alloca (len);
647 snprintf (userpwd, len, "%s:%s", username, password);
649 CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_USERPWD, userpwd));
651 /* HTTP Basic authentication is OK since we should be sending
652 * this only over HTTPS.
654 CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC));
656 /* Follow redirects. */
657 CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_FOLLOWLOCATION, (long) 1));
658 CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_MAXREDIRS, (long) 10));
660 /* Try to fetch the URI. */
661 r = CURL_CHECK_ERROR (curl_easy_perform, (curl));
663 /* Signal an error back to the main thread. */
664 error_str = g_strdup (curl_easy_strerror (r));
665 g_idle_add (main_login_error, error_str);
669 CURL_CHECK_ERROR (curl_easy_getinfo, (curl, CURLINFO_RESPONSE_CODE, &code));
670 DEBUG ("HTTP return code is %ld", code);
674 DEBUG ("login was successful");
678 error_str = g_strdup ("server rejected the username or password");
679 g_idle_add (main_login_error, error_str);
683 /* XXX If only glib had g_asprintf. */
684 error_str = g_strdup ("unexpected HTTP return code from server");
685 g_idle_add (main_login_error, error_str);
690 /* Called from the message loop. Refresh the list of VMs. */
692 refresh_vm_list (void)
701 DEBUG ("refreshing list of VMs");
702 ASSERT_IS_WUI_THREAD ();
704 /* Generate the vms URI from the base URI. */
705 len = strlen (uri) + 4 + 1;
706 vms_uri = g_alloca (len);
707 snprintf (vms_uri, len, "%s/vms", uri);
709 DEBUG ("vms URI %s", vms_uri);
711 /* Set the URI for libcurl. */
712 CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_URL, vms_uri));
714 /* We want to capture the output, so tell our write function
715 * to place the output into a buffer.
717 write_fn_start_capture ();
719 /* Try to fetch the URI. */
720 r = CURL_CHECK_ERROR (curl_easy_perform, (curl));
722 /* Signal an error back to the main thread. */
723 error_str = g_strdup (curl_easy_strerror (r));
724 g_idle_add (main_login_error, error_str);
728 CURL_CHECK_ERROR (curl_easy_getinfo, (curl, CURLINFO_RESPONSE_CODE, &code));
729 DEBUG ("HTTP return code is %ld", code);
734 /* Hmm - even though we previously logged in, the server is
735 * rejecting our attempts now with an authorization error.
736 * We move to the logged out state.
739 set_logged_in (FALSE);
740 error_str = g_strdup ("server rejected the username or password");
741 g_idle_add (main_login_error, error_str);
745 /* XXX If only glib had g_asprintf. */
746 error_str = g_strdup ("unexpected HTTP return code from server");
747 g_idle_add (main_status_error, error_str);
751 /* If we got here then we appear to have a correct
752 * XML document describing the list of VMs.
754 secs_between_refresh <<= 1;
756 xml = write_fn_finish_capture ();
758 parse_vmlist_from_xml (xml);
764 /* Functions to deal with the list of VMs, parsing it from the XML, etc.
766 * A vmlist is a GSList (glib singly-linked list) of vm structures.
767 * The caller must call free_vmlist to free up this list correctly.
771 free_vm (gpointer _vm, gpointer data)
773 struct vm *vm = (struct vm *) _vm;
775 g_free (vm->description);
778 g_free (vm->mac_addr);
783 free_vmlist (GSList *vmlist)
785 g_slist_foreach (vmlist, free_vm, NULL);
786 g_slist_free (vmlist);
790 copy_vm (struct vm *vm)
794 vm2 = g_memdup (vm, sizeof (*vm));
795 vm2->description = g_strdup (vm->description);
796 vm2->state = vm->state ? g_strdup (vm->state) : NULL;
797 vm2->uuid = vm->uuid ? g_strdup (vm->uuid) : NULL;
798 vm2->mac_addr = vm->mac_addr ? g_strdup (vm->mac_addr) : NULL;
803 compare_vm (gconstpointer _vm1, gconstpointer _vm2)
805 const struct vm *vm1 = (const struct vm *) _vm1;
806 const struct vm *vm2 = (const struct vm *) _vm2;
808 return strcmp (vm1->description, vm2->description);
811 static GSList *vmlist = NULL;
812 static gboolean vmlist_valid = FALSE;
813 static GStaticMutex vmlist_mutex;
815 /* Called from the main thread to find out if we have a valid vmlist. */
817 wui_thread_has_valid_vmlist (void)
821 ASSERT_IS_MAIN_THREAD ();
823 g_static_mutex_lock (&vmlist_mutex);
825 g_static_mutex_unlock (&vmlist_mutex);
829 /* Called from the main thread to find return the current vmlist. This
830 * actually returns a deep copy of it that the caller must free.
833 duplicate_and_insert_vm (gpointer _vm, gpointer _ret)
835 struct vm *vm = (struct vm *) _vm;
836 GSList **ret = (GSList **) _ret;
838 *ret = g_slist_prepend (*ret, copy_vm (vm));
842 wui_thread_get_vmlist (GSList **ret)
846 ASSERT_IS_MAIN_THREAD ();
851 g_static_mutex_lock (&vmlist_mutex);
852 if (!vmlist_valid) goto done;
854 g_slist_foreach (vmlist, duplicate_and_insert_vm, ret);
855 *ret = g_slist_sort (*ret, compare_vm);
859 g_static_mutex_unlock (&vmlist_mutex);
863 /* Called from the message loop in the WUI thread, with an XML document
864 * which we turn into a list of VM structures, and update the vmlist
868 parse_vmlist_from_xml (const char *xml)
870 xmlDocPtr doc = NULL;
874 GSList *new_vmlist = NULL;
877 /*DEBUG ("XML =\n%s", xml);*/
878 ASSERT_IS_WUI_THREAD ();
880 /* We don't really expect that we won't be able to parse the XML ... */
881 doc = xmlParseDoc ((const xmlChar *) xml);
883 DEBUG ("error parsing XML document, xml =\n%s", xml);
884 error_str = g_strdup ("error parsing XML document from remote server");
885 g_idle_add (main_status_error, error_str);
889 root = xmlDocGetRootElement (doc);
891 DEBUG ("XML document was empty");
892 error_str = g_strdup ("XML document was empty");
893 g_idle_add (main_status_error, error_str);
897 /* We expect the root element will be either "nil-classes"
898 * or "vms", with the former indicating an empty list of VMs.
900 if (xmlStrcmp (root->name, (const xmlChar *) "nil-classes") == 0) {
901 g_static_mutex_lock (&vmlist_mutex);
903 free_vmlist (vmlist);
905 g_static_mutex_unlock (&vmlist_mutex);
907 /* Signal to the main UI thread that the list has been updated. */
908 g_idle_add (main_vmlist_updated, NULL);
913 if (xmlStrcmp (root->name, (const xmlChar *) "vms") != 0) {
914 DEBUG ("unexpected root node in XML document, xml =\n%s", xml);
915 error_str = g_strdup ("unexpected root node in XML document");
916 g_idle_add (main_status_error, error_str);
920 /* The document is <vms> with a list of <vm> elements which
921 * we process in turn.
923 for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
924 if (xmlStrcmp (node->name, (const xmlChar *) "vm") == 0) {
925 vm = parse_vm_from_xml (node);
927 error_str = g_strdup ("could not parse <vm> element");
928 g_idle_add (main_status_error, error_str);
930 free_vmlist (new_vmlist);
933 new_vmlist = g_slist_prepend (new_vmlist, vm);
937 /* Successfully parsed all the <vm> nodes, so swap the old and new
940 g_static_mutex_lock (&vmlist_mutex);
942 free_vmlist (vmlist);
944 g_static_mutex_unlock (&vmlist_mutex);
946 /* Signal that the vmlist has been updated. */
947 g_idle_add (main_vmlist_updated, NULL);
950 /* Free up XML resources used before returning. */
951 if (doc) xmlFreeDoc (doc);
955 parse_vm_from_xml (xmlNodePtr node)
961 memset (&vm, 0, sizeof vm);
965 vm.mem_allocated = -1;
967 vm.vcpus_allocated = -1;
970 for (p = node->xmlChildrenNode; p != NULL; p = p->next) {
971 if (xmlStrcmp (p->name, (const xmlChar *) "description") == 0) {
972 str = xmlNodeGetContent (p);
974 vm.description = g_strdup ((char *) str);
978 else if (xmlStrcmp (p->name, (const xmlChar *) "host-id") == 0) {
979 str = xmlNodeGetContent (p);
981 vm.hostid = strtol ((char *) str, NULL, 10);
985 else if (xmlStrcmp (p->name, (const xmlChar *) "id") == 0) {
986 str = xmlNodeGetContent (p);
988 vm.id = strtol ((char *) str, NULL, 10);
992 else if (xmlStrcmp (p->name, (const xmlChar *) "memory-allocated") == 0) {
993 str = xmlNodeGetContent (p);
995 vm.mem_allocated = strtol ((char *) str, NULL, 10);
999 else if (xmlStrcmp (p->name, (const xmlChar *) "memory-used") == 0) {
1000 str = xmlNodeGetContent (p);
1002 vm.mem_used = strtol ((char *) str, NULL, 10);
1006 else if (xmlStrcmp (p->name, (const xmlChar *) "num-vcpus-allocated") == 0) {
1007 str = xmlNodeGetContent (p);
1009 vm.vcpus_allocated = strtol ((char *) str, NULL, 10);
1013 else if (xmlStrcmp (p->name, (const xmlChar *) "num-vcpus-used") == 0) {
1014 str = xmlNodeGetContent (p);
1016 vm.vcpus_used = strtol ((char *) str, NULL, 10);
1020 else if (xmlStrcmp (p->name, (const xmlChar *) "state") == 0) {
1021 str = xmlNodeGetContent (p);
1023 vm.state = g_strdup ((char *) str);
1027 else if (xmlStrcmp (p->name, (const xmlChar *) "uuid") == 0) {
1028 str = xmlNodeGetContent (p);
1030 vm.uuid = g_strdup ((char *) str);
1034 else if (xmlStrcmp (p->name, (const xmlChar *) "vnc-port") == 0) {
1035 str = xmlNodeGetContent (p);
1037 vm.vnc_port = strtol ((char *) str, NULL, 10);
1041 else if (xmlStrcmp (p->name, (const xmlChar *) "vnic-mac-addr") == 0) {
1042 str = xmlNodeGetContent (p);
1044 vm.mac_addr = g_strdup ((char *) str);
1050 /* Make sure we've got the required fields. */
1052 if (vm.description == NULL)
1053 DEBUG ("required field \"description\" missing from <vm> structure");
1054 else if (vm.hostid == -1)
1055 DEBUG ("required field \"description\" missing from <vm> structure");
1056 else if (vm.id == -1)
1057 DEBUG ("required field \"description\" missing from <vm> structure");
1058 else if (vm.vnc_port == -1)
1059 DEBUG ("required field \"vnc-port\" missing from <vm> structure");
1061 ret = g_memdup (&vm, sizeof vm);