From 06576813e9eee9338ade91bb2486a52af9507471 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 27 Nov 2008 17:21:55 +0000 Subject: [PATCH] Push daily update. --- Makefile.am | 5 ++- configure.ac | 11 +++++- internal.h | 3 ++ main.c | 10 ++++++ wui_thread.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1c98123..fdf7428 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,9 +19,12 @@ 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 diff --git a/configure.ac b/configure.ac index 12269e8..42d5550 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/internal.h b/internal.h index b512fc3..d838fde 100644 --- a/internal.h +++ b/internal.h @@ -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 --- a/main.c +++ b/main.c @@ -51,6 +51,12 @@ 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, diff --git a/wui_thread.c b/wui_thread.c index 0db43c8..8079f75 100644 --- a/wui_thread.c +++ b/wui_thread.c @@ -25,11 +25,14 @@ #include +#include + #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) { -- 1.8.3.1