Push daily update.
authorRichard Jones <rjones@redhat.com>
Thu, 27 Nov 2008 17:21:55 +0000 (17:21 +0000)
committerRichard Jones <rjones@redhat.com>
Thu, 27 Nov 2008 17:21:55 +0000 (17:21 +0000)
Makefile.am
configure.ac
internal.h
main.c
wui_thread.c

index 1c98123..fdf7428 100644 (file)
 bin_PROGRAMS = ovirt-viewer
 
 ovirt_viewer_SOURCES = main.c wui_thread.c internal.h
-ovirt_viewer_CFLAGS = $(OVIRT_VIEWER_CFLAGS) -Wall
+ovirt_viewer_CFLAGS = $(OVIRT_VIEWER_CFLAGS) -Wall -DCAINFO='"$(CAINFO)"'
 ovirt_viewer_LDADD = $(OVIRT_VIEWER_LIBS)
 
 EXTRA_DIST = $(PACKAGE).spec
 
 DISTCLEAN_FILES = $(PACKAGE).spec
+
+valgrind:
+       valgrind --leak-check=full ./ovirt-viewer$(EXEEXT) --debug
index 12269e8..42d5550 100644 (file)
@@ -23,17 +23,26 @@ dnl Basic C compiler environment.
 AC_PROG_INSTALL
 AC_PROG_CC
 AM_PROG_CC_C_O
+AC_EXEEXT
 
 dnl Check for required packages.
 dnl Note that we are using GLib threads, which are supported on Linux
 dnl and Windows, but possibly not on some obscure platforms.
 PKG_PROG_PKG_CONFIG
 PKG_CHECK_MODULES([OVIRT_VIEWER],
-       [gtk+-2.0 gtk-vnc-1.0 glib-2.0 libxml-2.0 gnutls gthread-2.0])
+       [gtk+-2.0 gtk-vnc-1.0 glib-2.0 libxml-2.0 gnutls gthread-2.0 libcurl])
 
 dnl Header files.
 AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h])
 
+dnl Default location for CA certificate bundle.
+AC_ARG_ENABLE([cainfo],
+       [AS_HELP_STRING([--enable-cainfo=PATH],
+         [Set the path to the CA certificate bundle.])],
+       [CAINFO=$enableval],
+       [CAINFO=$sysconfdir/pki/tls/certs/ca-bundle.crt])
+AC_SUBST([CAINFO])
+
 dnl Output.
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([Makefile])
index b512fc3..d838fde 100644 (file)
@@ -50,6 +50,9 @@ extern gboolean debug;
 #define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
 #define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
 
+extern const char *cainfo;
+extern gboolean check_cert;
+
 /* Communications between the main thread and the WUI thread.  For
  * an explanation of the threading model, please see the comment in
  * main().
diff --git a/main.c b/main.c
index 9c992f6..039cf39 100644 (file)
--- a/main.c
+++ b/main.c
 
 gboolean debug = 0;
 
+/* Usually /etc/pki/tls/certs/ca-bundle.crt unless overridden during
+ * configure or on the command line.
+ */
+const char *cainfo = CAINFO;
+gboolean check_cert = TRUE;
+
 /* Private functions. */
 static void start_ui (void);
 static GtkWidget *menu_item_new (int which_menu);
@@ -114,6 +120,10 @@ static const char *help_msg =
   "Use '" PACKAGE " --help' to see a list of available command line options";
 
 static const GOptionEntry options[] = {
+  { "cainfo", 0, 0, G_OPTION_ARG_STRING, &cainfo,
+    "set the path of the CA certificate bundle", NULL },
+  { "check-certificate", 0, 0, G_OPTION_ARG_NONE, &check_cert,
+    "if --no-check-certificate is passed we don't check the SSL certificate of the server", NULL },
   { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug,
     "turn on debugging messages", NULL },
   { "version", 'V', 0, G_OPTION_ARG_NONE, &print_version,
index 0db43c8..8079f75 100644 (file)
 
 #include <glib.h>
 
+#include <curl/curl.h>
+
 #include "internal.h"
 
 /* Private functions. */
 static gpointer wui_thread (gpointer data);
 static void wui_thread_send_quit (void);
+static void do_curl_init (void);
 static gboolean do_connect (void);
 static gboolean do_login (void);
 static void refresh_vm_list (void);
@@ -174,6 +177,8 @@ static void set_busy (gboolean);
 
 /* The private state of the WUI thread. */
 static int secs_between_refresh = 60;
+static CURL *curl = NULL;
+static char curl_error_buffer[CURL_ERROR_SIZE];
 static char *uri = NULL;
 static char *username = NULL;
 static char *password = NULL;
@@ -215,7 +220,7 @@ wui_thread (gpointer _queue)
     msg = (struct message *) _msg;
 
     if (msg) {
-      DEBUG ("received message %d", msg->type);
+      DEBUG ("received message with msg->type = %d", msg->type);
       quit = process_message (msg);
       /* Don't free any strings in the message - we've saved them. */
       g_free (msg);
@@ -306,6 +311,7 @@ process_message (struct message *msg)
 {
   switch (msg->type) {
   case QUIT:
+    if (curl) curl_easy_cleanup (curl);
     if (uri) g_free (uri);
     if (username) g_free (username);
     if (password) g_free (password);
@@ -314,6 +320,8 @@ process_message (struct message *msg)
     return 1;
 
   case CONNECT:
+    if (curl) curl_easy_cleanup (curl);
+    do_curl_init ();
     if (uri) g_free (uri);
     uri = msg->str1;
 
@@ -327,9 +335,14 @@ process_message (struct message *msg)
 
   case DISCONNECT:
     /* This just forgets the state. REST is connectionless. */
+    if (curl) curl_easy_cleanup (curl);
+    curl = NULL;
     if (uri) g_free (uri);
+    uri = NULL;
     if (username) g_free (username);
+    username = NULL;
     if (password) g_free (password);
+    password = NULL;
     set_connected (FALSE);
     set_logged_in (FALSE);
     break;
@@ -340,6 +353,10 @@ process_message (struct message *msg)
     if (password) g_free (password);
     password = msg->str2;
 
+    /* If we're not connected, this message just updates the
+     * username and password.  Otherwise if we are connected,
+     * try to login and grab the initial list of VMs.
+     */
     if (connected) {
       if (do_login ()) {
        set_logged_in (TRUE);
@@ -351,8 +368,10 @@ process_message (struct message *msg)
     break;
 
   case REFRESH_VM_LIST:
-    refresh_vm_list ();
-    secs_between_refresh = 60;
+    if (connected && logged_in) {
+      refresh_vm_list ();
+      secs_between_refresh = 60;
+    }
     break;
 
   default:
@@ -363,16 +382,90 @@ process_message (struct message *msg)
   return 0;
 }
 
-/* Try to connect to the current URI.  Returns true on success. */
+/* Macro for easy handling of CURL errors. */
+#define CURL_CHECK_ERROR(fn, args)                                     \
+  ({                                                                   \
+    CURLcode __r = fn args;                                            \
+    if (__r != CURLE_OK) {                                             \
+      fprintf (stderr, "%s: %s\n", #fn, curl_easy_strerror (__r));     \
+    }                                                                  \
+    __r;                                                               \
+  })
+
+static size_t
+write_fn (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  int bytes = size * nmemb;
+  return bytes;
+}
+
+static size_t
+header_fn (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  int bytes = size * nmemb;
+  return bytes;
+}
+
+/* Called from the message loop to initialize the CURL handle. */
+static void
+do_curl_init (void)
+{
+  DEBUG ("initializing libcurl");
+
+  curl = curl_easy_init ();
+  if (!curl) {            /* This is probably quite bad, so abort. */
+    DEBUG ("curl_easy_init failed");
+    abort ();
+  }
+
+  CURL_CHECK_ERROR (curl_easy_setopt,
+                   (curl, CURLOPT_CAINFO, cainfo));
+  CURL_CHECK_ERROR (curl_easy_setopt,
+                   (curl, CURLOPT_SSL_VERIFYHOST, check_cert ? 2 : 0));
+  CURL_CHECK_ERROR (curl_easy_setopt,
+                   (curl, CURLOPT_SSL_VERIFYPEER, check_cert ? 1 : 0));
+
+  CURL_CHECK_ERROR (curl_easy_setopt,
+                   (curl, CURLOPT_WRITEFUNCTION, write_fn));
+  CURL_CHECK_ERROR (curl_easy_setopt,
+                   (curl, CURLOPT_HEADERFUNCTION, header_fn));
+
+  /* This enables error messages in curl_easy_perform. */
+  CURL_CHECK_ERROR (curl_easy_setopt,
+                   (curl, CURLOPT_ERRORBUFFER, curl_error_buffer));
+
+  /* This enables cookie handling, using an internal cookiejar. */
+  CURL_CHECK_ERROR (curl_easy_setopt,
+                   (curl, CURLOPT_COOKIEFILE, ""));
+}
+
+/* Called from the message loop.  Try to connect to the current URI.
+ * Returns true on success.
+ */
 static gboolean
 do_connect (void)
 {
+  long code = 0;
+
   DEBUG ("connecting to uri %s", uri);
-  return FALSE;
+
+  /* Set the URI for libcurl. */
+  CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_URL, uri));
+
+  /* Try to fetch the URI. */
+  if (CURL_CHECK_ERROR (curl_easy_perform, (curl)) != CURLE_OK)
+    return FALSE;
+
+  CURL_CHECK_ERROR (curl_easy_getinfo, (curl, CURLINFO_RESPONSE_CODE, &code));
+  DEBUG ("HTTP return code is %ld", code);
+  if (code != 200 || code != 302 || code != 401)
+    return FALSE;
+
+  return TRUE;
 }
 
-/* Try to login to URI/login with the username and password given.
- * Returns true on success.
+/* Called from the message loop.  Try to login to 'URI/login' with the
+ * current username and password.  Returns true on success.
  */
 static gboolean
 do_login (void)
@@ -381,7 +474,7 @@ do_login (void)
   return FALSE;
 }
 
-/* Refresh the list of VMs. */
+/* Called from the message loop.  Refresh the list of VMs. */
 static void
 refresh_vm_list (void)
 {