[Pkg-libvirt-commits] [SCM] libvirt ruby bindinds packaging branch, master, updated. debian/0.4.0-1

Guido Günther agx at sigxcpu.org
Tue Feb 7 21:11:44 UTC 2012


The following commit has been merged in the master branch:
commit 7bf70bab8c51e2eec9f44a4515ddab7e8f5dfcd9
Author: Guido Günther <agx at sigxcpu.org>
Date:   Tue Feb 7 19:40:38 2012 +0100

    New upstream version 0.4.0

diff --git a/NEWS b/NEWS
index f607975..c26c071 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,68 @@
+2011-07-27 0.4.0
+  * Updated Domain class, implementing dom.memory_parameters=,
+    dom.memory_parameters, dom.updated?, dom.migrate2, dom.migrate_to_uri2,
+    dom.migrate_set_max_speed, dom.qemu_monitor_command, dom.blkio_parameters,
+    dom.blkio_parameters=, dom.state, dom.open_console, dom.screenshot, and
+    dom.inject_nmi
+  * Implementation of the Stream class, which covers the libvirt virStream APIs
+  * Add the ability to build against non-system libvirt libraries
+  * Updated Error object, which now includes the libvirt code, component and
+    level of the error, as well as all of the error constants from libvirt.h
+  * Updated Connect class, implementing conn.sys_info, conn.stream,
+    conn.interface_change_begin, conn.interface_change_commit, and
+    conn.interface_change_rollback
+  * Updated StorageVol class, implementing vol.download and vol.upload
+  * Various bugfixes
+
+2010-12-12 0.3.0
+  * Implementation of Libvirt::open_auth, Libvirt::event_register_impl
+  * Updated Connect class, implementing conn.compare_cpu, conn.baseline_cpu,
+    conn.domain_event_register_any, conn.domain_event_deregister_any,
+    conn.domain_event_register, conn.domain_event_deregister, and
+    conn.create_domain_xml.
+  * Updated Domain class, implementing dom.get_vcpus, dom.update_device,
+    dom.scheduler_type, dom.scheduler_parameters, dom.scheduler_parameters=,
+    dom.num_vcpus, dom.vcpus_flags=, and dom.qemu_monitor_command.
+  * Updated Interface class, implementing interface.free
+  * Many potential memory leaks have been fixed.
+  * Many bugfixes.
+  * Documentation update of many methods, including all of the lookup methods
+    that were missing before.
+
+2010-11-10
+  * Gem for version 0.2.0 pushed to rubygems.org
+
+2010-07-01 0.2.0
+  * Updated Storage class, implementing pool.active?, pool.persistent?,
+    pool.vol_create_xml_from.
+  * Updated Connect class, implementing conn.node_free_memory,
+    conn.node_cells_free_memory, conn.node_get_security_model, conn.encrypted?,
+    conn.libversion, and conn.secure?
+  * Updated Network class, implementing network.active? and network.persistent?
+  * Update Domain class, implementing conn.domain_xml_from_native,
+    conn.domain_xml_to_native, dom.migrate_to_uri,
+    dom.migrate_set_max_downtime, dom.managed_save, dom.has_managed_save?,
+    dom.managed_save_remove, dom.security_label, dom.block_stats,
+    dom.memory_stats, dom.blockinfo, dom.block_peek, dom.memory_peek,
+    dom.active?, dom.persistent?, dom.snapshot_create_xml,
+    dom.num_of_snapshots, dom.list_snapshots, dom.lookup_snapshot_by_name,
+    dom.has_current_snapshot?, dom.revert_to_snapshot, dom.current_snapshot,
+    snapshot.xml_desc, snapshot.delete, dom.job_info, and dom.abort_job.
+  * Implementation of the NodeDevice class.
+  * Implementation of the Secret class.
+  * Implementation of the NWFilter class.
+  * Implementation of the Interface class.
+  * Conversion of the development tree to git.
+  * New maintainer (Chris Lalancette). David Lutterkort has agreed to transfer
+    maintainership since he is not actively involved in their development
+    anymore.
+
+2008-11-18 0.1.0
+  * Add binding for virConnectFindStoragePoolSources (clalance)
+  * Fix dom_migrate (clalance)
+  * Add the MIGRATE_LIVE (enum virDomainMigrateFlags) flag
+  * Slight improvements of the unit tests
+
 2008-04-15 0.0.7
   * Binding for virDomainMigrate
   * Fix crash caused by using virResetError
diff --git a/README b/README
index 1c7ed49..011ea22 100644
--- a/README
+++ b/README
@@ -7,7 +7,7 @@ Usage
 -----
 
 In your ruby code, do a "require 'libvirt'"; to obtain a connection, use
-'Libvirt::open' or 'Libvirt::openReadOnly'. See tests/*.rb for more
+'Libvirt::open' or 'Libvirt::open_read_only'. See tests/*.rb for more
 examples.
 
 Hacking
@@ -23,4 +23,30 @@ To run against the checkout, make sure you set RUBYLIB (assuming DIR is the
 toplevel of your source checkout):
 
   export RUBYLIB=$dir/lib:$dir/ext/libvirt
-  ruby -rlibvirt -e 'puts Libvirt::version("xen")[0]'
+  ruby -rlibvirt -e 'puts Libvirt::version[0]'
+
+Notes
+-----
+As of June 24, 2011, the ruby-libvirt bindings support all of the libvirt
+APIs up to libvirt commit hash 2c5ded6e8269463d2daab3dfa0ecae1477730ee2
+with the following exceptions:
+
+- virConnectRef
+- virDomainGetConnect
+- virDomainRef
+- virDomainOpenConsole
+- virNetworkGetConnect
+- virNetworkRef
+- virInterfaceGetConnect
+- virInterfaceRef
+- virStoragePoolGetConnect
+- virStoragePoolRef
+- virStorageVolGetConnect
+- virStorageVolRef
+- virNodeDeviceRef
+- virSecretGetConnect
+- virSecretRef
+- virStreamRef
+- virNWFilterRef
+- virEventRegisterDefaultImpl
+- virEventRunDefaultImpl
diff --git a/README.rdoc b/README.rdoc
index eb37a7e..3514843 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -2,10 +2,27 @@
 
 The module Libvirt provides bindings to libvirt[http://libvirt.org]
 
-The various +*Ptr+ types in Libvirt map loosely to the following Ruby classes:
+The various *Ptr types in Libvirt map loosely to the following Ruby classes:
 
 [virConnectPtr] Libvirt::Connect
+[virNodeInfoPtr] Libvirt::Connect::Nodeinfo
+[virSecurityModelPtr] Libvirt::Connect::NodeSecurityModel
 [virDomainPtr]  Libvirt::Domain
 [virDomainInfoPtr]  Libvirt::Domain::Info
+[virDomainInterfaceStatsPtr] Libvirt::Domain::InterfaceInfo
+[virSecurityLabelPtr] Libvirt::Domain::SecurityLabel
+[virDomainBlockStatsPtr] Libvirt::Domain::BlockStats
+[virDomainMemoryStatPtr] Libvirt::Domain::MemoryStats
+[virDomainBlockInfoPtr] Libvirt::Domain::BlockInfo
+[virDomainSnapshotPtr] Libvirt::Domain::Snapshot
+[virDomainJobInfoPtr] Libvirt::Domain::JobInfo
 [virNetworkPtr] Libvirt::Network
-
+[virNWFilterPtr] Libvirt::NWFilter
+[virNodeDevicePtr] Libvirt::NodeDevice
+[virStoragePoolPtr] Libvirt::StoragePool
+[virStoragePoolInfoPtr] Libvirt::StoragePoolInfo
+[virStorageVolPtr] Libvirt::StorageVol
+[virStorageVolInfoPtr] Libvirt::StorageVolInfo
+[virSecretPtr] Libvirt::Secret
+[virInterfacePtr] Libvirt::Interface
+[virStreamPtr] Libvirt::Stream
diff --git a/Rakefile b/Rakefile
index 62f3ae2..8996716 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,7 +1,7 @@
 # -*- ruby -*-
 # Rakefile: build ruby libvirt bindings
 #
-# Copyright (C) 2007 Red Hat, Inc.
+# Copyright (C) 2007,2010 Red Hat, Inc.
 #
 # Distributed under the GNU Lesser General Public License v2.1 or later.
 # See COPYING for details
@@ -13,78 +13,119 @@ require 'rake/clean'
 require 'rake/rdoctask'
 require 'rake/testtask'
 require 'rake/gempackagetask'
+require 'rbconfig'
 
 PKG_NAME='ruby-libvirt'
-PKG_VERSION='0.0.7'
+PKG_VERSION='0.4.0'
 
 EXT_CONF='ext/libvirt/extconf.rb'
 MAKEFILE="ext/libvirt/Makefile"
 LIBVIRT_MODULE="ext/libvirt/_libvirt.so"
 SPEC_FILE="ruby-libvirt.spec"
-LIBVIRT_SRC=LIBVIRT_MODULE.gsub(/.so$/, ".c")
+LIBVIRT_SRC=Dir.glob("ext/libvirt/*.c")
+LIBVIRT_SRC << MAKEFILE
 
 #
 # Additional files for clean/clobber
 #
 
-CLEAN.include "**/*~"
+CLEAN.include [ "ext/**/*.o", LIBVIRT_MODULE,
+                "ext/**/depend" ]
 
-CLOBBER.include [ "config.save",
-                  "ext/**/*.o", LIBVIRT_MODULE,
-                  "ext/**/depend", "ext/**/mkmf.log", 
+CLOBBER.include [ "config.save", "ext/**/mkmf.log", "ext/**/extconf.h",
                   MAKEFILE ]
 
 #
 # Build locally
 #
-# FIXME: We can't get rid of install.rb yet, since there's no way
-# to pass config options to extconf.rb
 file MAKEFILE => EXT_CONF do |t|
     Dir::chdir(File::dirname(EXT_CONF)) do
-         unless sh "ruby #{File::basename(EXT_CONF)}"
-             $stderr.puts "Failed to run extconf"
-             break
-         end
+        extra = ""
+        args = ARGV.grep(/^--with-libvirt-include=/)
+        extra += args[0].chomp unless args.empty?
+        args = ARGV.grep(/^--with-libvirt-lib=/)
+        extra += " " + args[0].chomp unless args.empty?
+
+        unless sh "ruby #{File::basename(EXT_CONF)} #{extra}"
+            $stderr.puts "Failed to run extconf"
+            break
+        end
     end
 end
-file LIBVIRT_MODULE => [ MAKEFILE, LIBVIRT_SRC ] do |t|
+file LIBVIRT_MODULE => LIBVIRT_SRC do |t|
     Dir::chdir(File::dirname(EXT_CONF)) do
-         unless sh "make"
-             $stderr.puts "make failed"
-             break
-         end
+        unless sh "make"
+            $stderr.puts "make failed"
+            break
+        end
      end
 end
 desc "Build the native library"
 task :build => LIBVIRT_MODULE
 
+#
+# Test task
+#
+
 Rake::TestTask.new(:test) do |t|
-    t.test_files = FileList['tests/tc_*.rb']
+    t.test_files = [ 'tests/test_conn.rb', 'tests/test_domain.rb',
+                     'tests/test_interface.rb', 'tests/test_network.rb',
+                     'tests/test_nodedevice.rb', 'tests/test_nwfilter.rb',
+                     'tests/test_open.rb', 'tests/test_secret.rb',
+                     'tests/test_storage.rb' ]
     t.libs = [ 'lib', 'ext/libvirt' ]
 end
 task :test => :build
 
+#
+# Documentation tasks
+#
+
+RDOC_FILES = FileList[ "README.rdoc", "lib/libvirt.rb",
+                       "ext/libvirt/_libvirt.c", "ext/libvirt/connect.c",
+                       "ext/libvirt/domain.c", "ext/libvirt/interface.c",
+                       "ext/libvirt/network.c", "ext/libvirt/nodedevice.c",
+                       "ext/libvirt/nwfilter.c", "ext/libvirt/secret.c",
+                       "ext/libvirt/storage.c", "ext/libvirt/stream.c" ]
+
 Rake::RDocTask.new do |rd|
     rd.main = "README.rdoc"
     rd.rdoc_dir = "doc/site/api"
-    rd.rdoc_files.include("README.rdoc", "lib/**/*.rb", "ext/**/*.[ch]")
+    rd.rdoc_files.include(RDOC_FILES)
+end
+
+Rake::RDocTask.new(:ri) do |rd|
+    rd.main = "README.rdoc"
+    rd.rdoc_dir = "doc/ri"
+    rd.options << "--ri-system"
+    rd.rdoc_files.include(RDOC_FILES)
+end
+
+#
+# Splint task
+#
+
+task :splint => [ MAKEFILE ] do |t|
+    Dir::chdir(File::dirname(EXT_CONF)) do
+        unless sh "splint -I" + Config::CONFIG['vendorarchdir'] + " *.c"
+            $stderr.puts "Failed to run splint"
+            break
+        end
+    end
 end
 
 #
 # Package tasks
 #
 
-PKG_FILES = FileList[
-  "Rakefile", "COPYING", "README", "NEWS", "README.rdoc",
-  "lib/**/*.rb",
-  "ext/**/*.[ch]", "ext/**/MANIFEST", "ext/**/extconf.rb",
-  "tests/**/*",
-  "spec/**/*"
-]
+PKG_FILES = FileList[ "Rakefile", "COPYING", "README", "NEWS", "README.rdoc",
+                      "lib/**/*.rb",
+                      "ext/**/*.[ch]", "ext/**/MANIFEST", "ext/**/extconf.rb",
+                      "tests/**/*",
+                      "spec/**/*" ]
 
-DIST_FILES = FileList[
-  "pkg/*.src.rpm",  "pkg/*.gem",  "pkg/*.zip", "pkg/*.tgz"
-]
+DIST_FILES = FileList[ "pkg/*.src.rpm",  "pkg/*.gem",  "pkg/*.zip",
+                       "pkg/*.tgz" ]
 
 SPEC = Gem::Specification.new do |s|
     s.name = PKG_NAME
@@ -93,12 +134,11 @@ SPEC = Gem::Specification.new do |s|
     s.homepage = "http://libvirt.org/ruby/"
     s.summary = "Ruby bindings for LIBVIRT"
     s.files = PKG_FILES
-    s.autorequire = "libvirt"
     s.required_ruby_version = '>= 1.8.1'
     s.extensions = "ext/libvirt/extconf.rb"
-    s.description = <<EOF
-Provides bindings for libvirt.
-EOF
+    s.author = "David Lutterkort, Chris Lalancette"
+    s.rubyforge_project = "None"
+    s.description = "Ruby bindings for libvirt."
 end
 
 Rake::GemPackageTask.new(SPEC) do |pkg|
@@ -106,14 +146,6 @@ Rake::GemPackageTask.new(SPEC) do |pkg|
     pkg.need_zip = true
 end
 
-desc "Update the ruby-libvirt site"
-task :site => [ :rdoc ] do |t|
-    system("rsync -av doc/site/ libvirt:/data/www/libvirt.org/ruby/")
-    if $? != 0
-        raise "rsync failed: #{$?}"
-    end
-end
-
 desc "Build (S)RPM for #{PKG_NAME}"
 task :rpm => [ :package ] do |t|
     system("sed -e 's/@VERSION@/#{PKG_VERSION}/' #{SPEC_FILE} > pkg/#{SPEC_FILE}")
@@ -125,15 +157,3 @@ task :rpm => [ :package ] do |t|
         end
     end
 end
-
-desc "Release a version to the site"
-task :dist => [ :rpm ] do |t|
-    puts "Copying files"
-    unless sh "scp -p #{DIST_FILES.to_s} libvirt:/data/www/libvirt.org/ruby/download"
-        $stderr.puts "Copy to libvirt failed"
-        break
-    end
-    puts "Commit and tag #{PKG_VERSION}"
-    system "hg commit -m 'Released version #{PKG_VERSION}'"
-    system "hg tag -m 'Tag release #{PKG_VERSION}' #{PKG_NAME}-#{PKG_VERSION}"
-end
diff --git a/ext/libvirt/_libvirt.c b/ext/libvirt/_libvirt.c
index a1b6fae..0e7e0df 100644
--- a/ext/libvirt/_libvirt.c
+++ b/ext/libvirt/_libvirt.c
@@ -1,7 +1,7 @@
 /*
  * libvirt.c: Ruby bindings for libvirt
  *
- * Copyright (C) 2007 Red Hat Inc.
+ * Copyright (C) 2007,2010 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,1888 +24,987 @@
 #include <libvirt/libvirt.h>
 #include <libvirt/virterror.h>
 #include "extconf.h"
+#include "common.h"
+#include "storage.h"
+#include "connect.h"
+#include "network.h"
+#include "nodedevice.h"
+#include "secret.h"
+#include "nwfilter.h"
+#include "interface.h"
+#include "domain.h"
+#include "stream.h"
 
-static VALUE m_libvirt;
-static VALUE c_connect;
-static VALUE c_domain;
-static VALUE c_domain_info;
-#if HAVE_TYPE_VIRNETWORKPTR
-static VALUE c_network;
-#endif
-static VALUE c_libvirt_version;
-static VALUE c_node_info;
-#if HAVE_TYPE_VIRSTORAGEPOOLPTR
-static VALUE c_storage_pool;
-static VALUE c_storage_pool_info;
-#endif
-#if HAVE_TYPE_VIRSTORAGEVOLPTR
-static VALUE c_storage_vol;
-static VALUE c_storage_vol_info;
-#endif
-
-
-// define additional errors here
-static VALUE e_Error;                   // Error - generic error
-static VALUE e_ConnectionError;         // ConnectionError - error durring connection establishment
-static VALUE e_DefinitionError;         // DefinitionError - error during data definition
-static VALUE e_RetrieveError;           // RetrievalError - error during data retrieval
-
-/*
- * Internal helpers
- */
-
-/* Macros to ease some of the boilerplate */
-
-#define generic_free(kind, p)                                           \
-    do {                                                                \
-        int r;                                                          \
-        r = vir##kind##Free((vir##kind##Ptr) p);                        \
-        if (r < 0)                                                      \
-            rb_raise(rb_eSystemCallError, # kind " free failed");       \
-    } while(0);
-
-#define generic_get(kind, v)                                            \
-    do {                                                                \
-        vir##kind##Ptr ptr;                                             \
-        Data_Get_Struct(v, vir##kind, ptr);                             \
-        if (!ptr)                                                       \
-            rb_raise(rb_eArgError, #kind " has been freed");            \
-        return ptr;                                                     \
-    } while (0);
-
-static VALUE generic_new(VALUE klass, void *ptr, VALUE conn,
-                         RUBY_DATA_FUNC free_func) {
-    VALUE result;
-    result = Data_Wrap_Struct(klass, NULL, free_func, ptr);
-    rb_iv_set(result, "@connection", conn);
-    return result;
-}
-
-/* Error handling */
-#define _E(cond, excep) \
-    do { if (cond) vir_error(excep); } while(0)
-
-NORETURN(static void vir_error(VALUE exception));
-
-static void vir_error(VALUE exception) {
-    rb_exc_raise(exception);
-}
-
-static VALUE create_error(VALUE error, const char* method, const char* msg,
-                          virConnectPtr conn) {
-    VALUE ruby_errinfo;
-    virErrorPtr err;
-
-    if (msg == NULL || strlen(msg) == 0) {
-        char *defmsg;
-        size_t len;
-        len = snprintf(NULL, 0, "Call to function %s failed", method) + 1;
-        defmsg = ALLOC_N(char, len);
-        snprintf(defmsg, len, "Call to function %s failed", method);
-        ruby_errinfo = rb_exc_new2(error, defmsg);
-        free(defmsg);
-    } else {
-        ruby_errinfo = rb_exc_new2(error, msg);
-    }
-    rb_iv_set(ruby_errinfo, "@libvirt_function_name", rb_str_new2(method));
-
-    if (conn == NULL)
-        err = virGetLastError();
-    else
-        err = virConnGetLastError(conn);
-
-    if (err != NULL && err->message != NULL) {
-        rb_iv_set(ruby_errinfo, "@libvirt_message", rb_str_new2(err->message));
-    }
-
-    return ruby_errinfo;
-};
-
-
-/* Connections */
-static void connect_close(void *p) {
-    int r;
-
-    if (!p)
-        return;
-    r = virConnectClose((virConnectPtr) p);
-    _E(r < 0, create_error(rb_eSystemCallError, "connect_close",
-                           "Connection close failed", p));
-}
-
-static VALUE connect_new(virConnectPtr p) {
-    return Data_Wrap_Struct(c_connect, NULL, connect_close, p);
-}
-
-static virConnectPtr connect_get(VALUE s) {
-    generic_get(Connect, s);
-}
-
-static VALUE conn_attr(VALUE s) {
-    if (rb_obj_is_instance_of(s, c_connect) != Qtrue) {
-        s = rb_iv_get(s, "@connection");
-    }
-    if (rb_obj_is_instance_of(s, c_connect) != Qtrue) {
-        rb_raise(rb_eArgError, "Expected Connection object");
-    }
-    return s;
-}
-
-static virConnectPtr conn(VALUE s) {
-    s = conn_attr(s);
-    virConnectPtr conn;
-    Data_Get_Struct(s, virConnect, conn);
-    if (!conn)
-        rb_raise(rb_eArgError, "Connection has been closed");
-    return conn;
-}
-
-/* Domains */
-static void domain_free(void *d) {
-    generic_free(Domain, d);
-}
-
-static virDomainPtr domain_get(VALUE s) {
-    generic_get(Domain, s);
-}
-
-static VALUE domain_new(virDomainPtr d, VALUE conn) {
-    return generic_new(c_domain, d, conn, domain_free);
-}
-
-/* Network */
-#if HAVE_TYPE_VIRNETWORKPTR
-static void network_free(void *d) {
-    generic_free(Network, d);
-}
-
-static virNetworkPtr network_get(VALUE s) {
-    generic_get(Network, s);
-}
-
-static VALUE network_new(virNetworkPtr n, VALUE conn) {
-    return generic_new(c_network, n, conn, network_free);
-}
-#endif
-
-#if HAVE_TYPE_VIRSTORAGEPOOLPTR
-/* StoragePool */
-static void pool_free(void *d) {
-    generic_free(StoragePool, d);
-}
-
-static virStoragePoolPtr pool_get(VALUE s) {
-    generic_get(StoragePool, s);
-}
-
-static VALUE pool_new(virStoragePoolPtr n, VALUE conn) {
-    return generic_new(c_storage_pool, n, conn, pool_free);
-}
-#endif
-
-/* StorageVol */
-#if HAVE_TYPE_VIRSTORAGEVOLPTR
-static void vol_free(void *d) {
-    generic_free(StorageVol, d);
-}
- 
-static virStorageVolPtr vol_get(VALUE s) {
-    generic_get(StorageVol, s);
-}
- 
-static VALUE vol_new(virStorageVolPtr n, VALUE conn) {
-    return generic_new(c_storage_vol, n, conn, vol_free);
-}
-#endif
-
-/*
- * Code generating macros.
- *
- * We only generate function bodies, not the whole function
- * declaration.
- */
-
-/*
- * Generate a call to a virConnectNumOf... function. C is the Ruby VALUE
- * holding the connection and OBJS is a token indicating what objects to
- * get the number of, e.g. 'Domains'
- */
-#define gen_conn_num_of(c, objs)                                        \
-    do {                                                                \
-        int result;                                                     \
-        virConnectPtr conn = connect_get(c);                            \
-                                                                        \
-        result = virConnectNumOf##objs(conn);                           \
-        _E(result < 0, create_error(e_RetrieveError, "virConnectNumOf" # objs, "", conn));                \
-                                                                        \
-        return INT2NUM(result);                                         \
-    } while(0)
-
-/*
- * Generate a call to a virConnectList... function. S is the Ruby VALUE
- * holding the connection and OBJS is a token indicating what objects to
- * get the number of, e.g. 'Domains' The list function must return an array
- * of strings, which is returned as a Ruby array
- */
-#define gen_conn_list_names(s, objs)                                    \
-    do {                                                                \
-        int i, r, num;                                                  \
-        char **names;                                                   \
-        virConnectPtr conn = connect_get(s);                            \
-        VALUE result;                                                   \
-                                                                        \
-        num = virConnectNumOf##objs(conn);                              \
-        _E(num < 0, create_error(e_RetrieveError, "virConnectNumOf" # objs, "", conn));   \
-                                                                        \
-        names = ALLOC_N(char *, num);                                   \
-        r = virConnectList##objs(conn, names, num);                     \
-        if (r < 0) {                                                    \
-            free(names);                                                \
-            _E(r < 0, create_error(e_RetrieveError, "virConnectList" # objs, "", conn));  \
-        }                                                               \
-                                                                        \
-        result = rb_ary_new2(num);                                      \
-        for (i=0; i<num; i++) {                                         \
-            rb_ary_push(result, rb_str_new2(names[i]));                 \
-            free(names[i]);                                             \
-        }                                                               \
-        free(names);                                                    \
-        return result;                                                  \
-    } while(0)
-
-/* Generate a call to a function FUNC which returns an int error, where -1
- * indicates error and 0 success. The Ruby function will return Qnil on
- * success and throw an exception on error.
- */
-#define gen_call_void(func, conn, args...)                              \
-    do {                                                                \
-        int _r_##func;                                                  \
-        _r_##func = func(args);                                         \
-        _E(_r_##func < 0, create_error(e_Error, #func, "", conn));      \
-        return Qnil;                                                    \
-    } while(0)
-
-/* Generate a call to a function FUNC which returns a string. The Ruby
- * function will return the string on success and throw an exception on
- * error. The string returned by FUNC is freed if dealloc is true.
- */
-#define gen_call_string(func, conn, dealloc, args...)                   \
-    do {                                                                \
-        const char *str;                                                \
-        VALUE result;                                                   \
-                                                                        \
-        str = func(args);                                               \
-        _E(str == NULL, create_error(e_Error, # func, "", conn));       \
-                                                                        \
-        result = rb_str_new2(str);                                      \
-        if (dealloc)                                                    \
-            free((void *) str);                                         \
-        return result;                                                  \
-    } while(0)
-
-/* Generate a call to vir##KIND##Free and return Qnil. Set the the embedded
- * vir##KIND##Ptr to NULL. If that pointer is already NULL, do nothing.
- */
-#define gen_call_free(kind, s)                                          \
-    do {                                                                \
-        vir##kind##Ptr ptr;                                             \
-        Data_Get_Struct(s, vir##kind, ptr);                             \
-        if (ptr != NULL) {                                              \
-            int r = vir##kind##Free(ptr);                               \
-            _E(r < 0, create_error(e_Error, "vir" #kind "Free", "", conn(s))); \
-            DATA_PTR(s) = NULL;                                         \
-        }                                                               \
-        return Qnil;                                                    \
-    } while (0)
-
-/*
- * Module Libvirt
- */
-
-/*
- * call-seq:
- *   Libvirt::version(type) -> [ libvirt_version, type_version ]
- *
- * Call
- * +virGetVersion+[http://www.libvirt.org/html/libvirt-libvirt.html#virGetVersion]
- * to get the version of libvirt and of the hypervisor TYPE. Returns an
- * array with two entries of type Libvirt::Version.
- *
- */
-VALUE libvirt_version(VALUE m, VALUE t) {
-    unsigned long libVer;
-    const char *type = NULL;
-    unsigned long typeVer;
-    int r;
-    VALUE result, argv[2];
-
-    type = StringValueCStr(t);
-    r = virGetVersion(&libVer, type, &typeVer);
-    if (r < 0)
-        rb_raise(rb_eArgError, "Failed to get version for %s", type);
-
-    result = rb_ary_new2(2);
-    argv[0] = rb_str_new2("libvirt");
-    argv[1] = ULONG2NUM(libVer);
-    rb_ary_push(result, rb_class_new_instance(2, argv, c_libvirt_version));
-    argv[0] = t;
-    argv[1] = ULONG2NUM(typeVer);
-    rb_ary_push(result, rb_class_new_instance(2, argv, c_libvirt_version));
-    return result;
-}
-
-/*
- * call-seq:
- *   Libvirt::open(url) -> Libvirt::Connect
- *
- * Open a connection to URL with virConnectOpen[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpen]
- */
-VALUE libvirt_open(VALUE m, VALUE url) {
-    char *str = NULL;
-
-    if (url) {
-        str = StringValueCStr(url);
-        if (!str)
-            rb_raise(rb_eTypeError, "expected string");
-    }
-    virConnectPtr ptr = virConnectOpen(str);
-    if (!ptr)
-        rb_raise(e_ConnectionError, "Failed to open %s", str);
-    return connect_new(ptr);
-}
-
-/*
- * call-seq:
- *   Libvirt::openReadOnly(url) -> Libvirt::Connect
- *
- * Open a read-only connection to URL with
- * virConnectOpenReadOnly[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpenReadOnly]
- */
-VALUE libvirt_open_read_only(VALUE m, VALUE url) {
-    char *str = NULL;
-
-    if (url) {
-        str = StringValueCStr(url);
-        if (!str)
-            rb_raise(rb_eTypeError, "expected string");
-    }
-    virConnectPtr ptr = virConnectOpenReadOnly(str);
-    if (!ptr)
-        rb_raise(e_ConnectionError, "Failed to open %s readonly", str);
-    return connect_new(ptr);
-}
-
-/*
- * Class Libvirt::Connect
- */
-
-/*
- * call-seq:
- *   conn.close
- *
- * Close the connection
- */
-VALUE libvirt_conn_close(VALUE s) {
-    virConnectPtr conn;
-    Data_Get_Struct(s, virConnect, conn);
-    if (conn) {
-        connect_close(conn);
-        DATA_PTR(s) = NULL;
-    }
-    return Qnil;
-}
-
-/*
- * call-seq:
- *   conn.closed?
- *
- * Return +true+ if the connection is closed, +false+ if it is open
- */
-VALUE libvirt_conn_closed_p(VALUE s) {
-    virConnectPtr conn;
-    Data_Get_Struct(s, virConnect, conn);
-    return (conn==NULL) ? Qtrue : Qfalse;
-}
-
-/*
- * call-seq:
- *   conn.type -> string
- *
- * Call +virConnectGetType+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetType]
- */
-VALUE libvirt_conn_type(VALUE s) {
-    gen_call_string(virConnectGetType, connect_get(s), 0,
-                    connect_get(s));
-}
-
-/*
- * call-seq:
- *   conn.version -> fixnum
- *
- * Call +virConnectGetVersion+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetVersion]
- */
-VALUE libvirt_conn_version(VALUE s) {
-    int r;
-    unsigned long v;
-    virConnectPtr conn = connect_get(s);
-
-    r = virConnectGetVersion(conn, &v);
-    _E(r < 0, create_error(e_RetrieveError, "virConnectGetVersion", "", conn));
-
-    return ULONG2NUM(v);
-}
-
-/*
- * call-seq:
- *   conn.hostname -> string
- *
- * Call +virConnectGetHostname+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetHostname]
- */
-VALUE libvirt_conn_hostname(VALUE s) {
-    gen_call_string(virConnectGetHostname, connect_get(s), 1,
-                    connect_get(s));
-}
-
-/*
- * Call +virConnectGetURI+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetURI]
- */
-VALUE libvirt_conn_uri(VALUE s) {
-    virConnectPtr conn = connect_get(s);
-    gen_call_string(virConnectGetURI, conn, 1,
-                    conn);
-}
-
-/*
- * Call +virConnectGetMaxVcpus+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetMaxVcpus]
- */
-VALUE libvirt_conn_max_vcpus(VALUE s, VALUE type) {
-    int result;
-    virConnectPtr conn = connect_get(s);
-
-    result = virConnectGetMaxVcpus(conn, StringValueCStr(type));
-    _E(result < 0, create_error(e_RetrieveError, "virConnectGetMaxVcpus", "", conn));
-
-    return INT2NUM(result);
-}
-
-/*
- * Call +virNodeInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeGetInfo]
- */
-VALUE libvirt_conn_node_get_info(VALUE s){
-    int r;
-    virConnectPtr conn = connect_get(s);
-    virNodeInfo nodeinfo;
-    VALUE result;
-    VALUE modelstr;
-
-    r = virNodeGetInfo(conn, &nodeinfo);
-    _E(r < 0, create_error(e_RetrieveError, "virNodeGetInfo", "", conn));
-
-    modelstr = rb_str_new2(nodeinfo.model);
-
-    result = rb_class_new_instance(0, NULL, c_node_info);
-    rb_iv_set(result, "@model", modelstr);
-    rb_iv_set(result, "@memory", ULONG2NUM(nodeinfo.memory));
-    rb_iv_set(result, "@cpus", UINT2NUM(nodeinfo.cpus));
-    rb_iv_set(result, "@mhz", UINT2NUM(nodeinfo.mhz));
-    rb_iv_set(result, "@nodes", UINT2NUM(nodeinfo.nodes));
-    rb_iv_set(result, "@sockets", UINT2NUM(nodeinfo.sockets));
-    rb_iv_set(result, "@cores", UINT2NUM(nodeinfo.cores));
-    rb_iv_set(result, "@threads", UINT2NUM(nodeinfo.threads));
-    return result;
-}
-
-/*
- * Call +virConnectGetCapabilities+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetCapabilities]
- */
-VALUE libvirt_conn_capabilities(VALUE s) {
-    virConnectPtr conn = connect_get(s);
-    gen_call_string(virConnectGetCapabilities, conn, 1,
-                    conn);
-}
-
-/*
- * Call +virConnectNumOfDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDomains]
- */
-VALUE libvirt_conn_num_of_domains(VALUE s) {
-    gen_conn_num_of(s, Domains);
-}
-
-/*
- * Call +virConnectListDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDomains]
- */
-VALUE libvirt_conn_list_domains(VALUE s) {
-    int i, r, num, *ids;
-    virConnectPtr conn = connect_get(s);
-    VALUE result;
-
-    num = virConnectNumOfDomains(conn);
-    _E(num < 0, create_error(e_RetrieveError, "virConnectNumOfDomains", "", conn));
-
-    ids = ALLOC_N(int, num);
-    r = virConnectListDomains(conn, ids, num);
-    if (r < 0) {
-        free(ids);
-        _E(r < 0, create_error(e_RetrieveError, "virConnectListDomains", "", conn));
-    }
-
-    result = rb_ary_new2(num);
-    for (i=0; i<num; i++) {
-        rb_ary_push(result, INT2NUM(ids[i]));
-    }
-    free(ids);
-    return result;
-}
-
-/*
- * Call +virConnectNumOfDefinedDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDefinedDomains]
- */
-VALUE libvirt_conn_num_of_defined_domains(VALUE s) {
-    gen_conn_num_of(s, DefinedDomains);
-}
-
-/*
- * Call +virConnectListDefinedDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDefinedDomains]
- */
-VALUE libvirt_conn_list_defined_domains(VALUE s) {
-    gen_conn_list_names(s, DefinedDomains);
-}
-
-/*
- * Call +virConnectNumOfNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfNetworks]
- */
-VALUE libvirt_conn_num_of_networks(VALUE s) {
-    gen_conn_num_of(s, Networks);
-}
-
-/*
- * Call +virConnectListNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListNetworks]
- */
-VALUE libvirt_conn_list_networks(VALUE s) {
-    gen_conn_list_names(s, Networks);
-}
-
-/*
- * Call +virConnectNumOfDefinedNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDefinedNetworks]
- */
-VALUE libvirt_conn_num_of_defined_networks(VALUE s) {
-    gen_conn_num_of(s, DefinedNetworks);
-}
-
-/*
- * Call +virConnectListDefinedNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDefinedNetworks]
- */
-VALUE libvirt_conn_list_defined_networks(VALUE s) {
-    gen_conn_list_names(s, DefinedNetworks);
-}
-
-#if HAVE_TYPE_VIRSTORAGEPOOLPTR
-/*
- * Call +virConnectListStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListStoragePools]
- */
-VALUE libvirt_conn_list_storage_pools(VALUE s) {
-    gen_conn_list_names(s, StoragePools);
-}
-
-/*
- * Call +virConnectNumOfStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfStoragePools]
- */
-VALUE libvirt_conn_num_of_storage_pools(VALUE s) {
-    gen_conn_num_of(s, StoragePools);
-}
-
-/*
- * Call +virConnectListDefinedStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDefinedStoragePools]
- */
-VALUE libvirt_conn_list_defined_storage_pools(VALUE s) {
-    gen_conn_list_names(s, DefinedStoragePools);
-}
-
-/*
- * Call +virConnectNumOfDefinedStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDefinedStoragePools]
- */
-VALUE libvirt_conn_num_of_defined_storage_pools(VALUE s) {
-    gen_conn_num_of(s, DefinedStoragePools);
-}
-#endif
-
-/*
- * Class Libvirt::Domain
- */
-VALUE libvirt_dom_migrate(VALUE s, VALUE dconn, VALUE flags,
-                           VALUE dname, VALUE uri, VALUE bandwidth) {
-    virDomainPtr ddom = NULL;
-
-    ddom = virDomainMigrate(domain_get(s), conn(dconn), NUM2UINT(flags),
-                            StringValueCStr(dname), StringValueCStr(uri),
-                            NUM2UINT(bandwidth));
-
-    _E(ddom == NULL,
-       create_error(e_Error, "virDomainMigrate", "", conn(dconn)));
-
-    return domain_new(ddom, dconn);
-}
-
-/*
- * Call +virDomainShutdown+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainShutdown]
- */
-VALUE libvirt_dom_shutdown(VALUE s) {
-    gen_call_void(virDomainShutdown, conn(s),
-                  domain_get(s));
-}
-
-/*
- * Call +virDomainReboot+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainReboot]
- */
-VALUE libvirt_dom_reboot(int argc, VALUE *argv, VALUE s) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    gen_call_void(virDomainReboot, conn(s), 
-                  domain_get(s), NUM2UINT(flags));
-}
-
-/*
- * Call +virDomainDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainDestroy]
- */
-VALUE libvirt_dom_destroy(VALUE s) {
-    gen_call_void(virDomainDestroy, conn(s),
-                  domain_get(s));
-}
-
-/*
- * Call +virDomainSuspend+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSuspend]
- */
-VALUE libvirt_dom_suspend(VALUE s) {
-    gen_call_void(virDomainSuspend, conn(s),
-                  domain_get(s));
-}
-
-/*
- * Call +virDomainResume+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainResume]
- */
-VALUE libvirt_dom_resume(VALUE s) {
-    gen_call_void(virDomainResume, conn(s),
-                  domain_get(s));
-}
-
-/*
- * Call +virDomainSave+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSave]
- */
-VALUE libvirt_dom_save(VALUE s, VALUE to) {
-    gen_call_void(virDomainSave, conn(s),
-                  domain_get(s), StringValueCStr(to));
-}
-
-/*
- * Call +virDomainCoreDump+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCoreDump]
- */
-VALUE libvirt_dom_core_dump(int argc, VALUE *argv, VALUE s) {
-    VALUE to, flags;
-
-    rb_scan_args(argc, argv, "11", &to, &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    gen_call_void(virDomainCoreDump, conn(s),
-                  domain_get(s), StringValueCStr(to), NUM2UINT(flags));
-}
-
-/*
- * Call +virDomainRestore+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainRestore]
- */
-VALUE libvirt_dom_s_restore(VALUE klass, VALUE c, VALUE from) {
-    gen_call_void(virDomainRestore, connect_get(c),
-                  connect_get(c), StringValueCStr(from));
-}
-
-/*
- * call-seq:
- *   domain.info -> Libvirt::Domain::Info
- *
- * Call +virDomainGetInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetInfo]
- */
-VALUE libvirt_dom_info(VALUE s) {
-    virDomainPtr dom = domain_get(s);
-    virDomainInfo info;
-    int r;
-    VALUE result;
-
-    r = virDomainGetInfo(dom, &info);
-    _E(r < 0, create_error(e_RetrieveError, "virDomainGetInfo", "", conn(s)));
-
-    result = rb_class_new_instance(0, NULL, c_domain_info);
-    rb_iv_set(result, "@state", CHR2FIX(info.state));
-    rb_iv_set(result, "@max_mem", ULONG2NUM(info.maxMem));
-    rb_iv_set(result, "@memory", ULONG2NUM(info.memory));
-    rb_iv_set(result, "@nr_virt_cpu", INT2FIX((int) info.nrVirtCpu));
-    rb_iv_set(result, "@cpu_time", ULL2NUM(info.cpuTime));
-    return result;
-}
-
-
-/*
- * Call +virDomainGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetName]
- */
-VALUE libvirt_dom_name(VALUE s) {
-    gen_call_string(virDomainGetName, conn(s), 0,
-                    domain_get(s));
-}
-
-/*
- * Call +virDomainGetID+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetID]
- */
-VALUE libvirt_dom_id(VALUE s) {
-    virDomainPtr dom = domain_get(s);
-    unsigned int id;
-
-    id = virDomainGetID(dom);
-    _E(id < 0, create_error(e_RetrieveError, "virDomainGetID", "", conn(s)));
-
-    return UINT2NUM(id);
-}
-
-/*
- * Call +virDomainGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetUUIDString]
- */
-VALUE libvirt_dom_uuid(VALUE s) {
-    virDomainPtr dom = domain_get(s);
-    char uuid[VIR_UUID_STRING_BUFLEN];
-    int r;
-
-    r = virDomainGetUUIDString(dom, uuid);
-    _E(r < 0, create_error(e_RetrieveError, "virDomainGetUUIDString", "", conn(s)));
-
-    return rb_str_new2((char *) uuid);
-}
-
-/*
- * Call +virDomainGetOSType+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetOSType]
- */
-VALUE libvirt_dom_os_type(VALUE s) {
-    gen_call_string(virDomainGetOSType, conn(s), 1,
-                    domain_get(s));
-}
-
-/*
- * Call +virDomainGetMaxMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetMaxMemory]
- */
-VALUE libvirt_dom_max_memory(VALUE s) {
-    virDomainPtr dom = domain_get(s);
-    unsigned long max_memory;
-
-    max_memory = virDomainGetMaxMemory(dom);
-    _E(max_memory == 0, create_error(e_RetrieveError, "virDomainGetMaxMemory", "", conn(s)));
-
-    return ULONG2NUM(max_memory);
-}
-
-/*
- * Call +virDomainSetMaxMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetMaxMemory]
- */
-VALUE libvirt_dom_max_memory_set(VALUE s, VALUE max_memory) {
-    virDomainPtr dom = domain_get(s);
-    int r;
-
-    r = virDomainSetMaxMemory(dom, NUM2ULONG(max_memory));
-    _E(r < 0, create_error(e_DefinitionError, "virDomainSetMaxMemory", "", conn(s)));
-
-    return ULONG2NUM(max_memory);
-}
-
-/*
- * Call +virDomainSetMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetMemory]
- */
-VALUE libvirt_dom_memory_set(VALUE s, VALUE memory) {
-    virDomainPtr dom = domain_get(s);
-    int r;
-
-    r = virDomainSetMemory(dom, NUM2ULONG(memory));
-    _E(r < 0, create_error(e_DefinitionError, "virDomainSetMemory", "", conn(s)));
-
-    return ULONG2NUM(memory);
-}
-
-/*
- * Call +virDomainGetMaxVcpus+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetMaxVcpus]
- */
-VALUE libvirt_dom_max_vcpus(VALUE s) {
-    virDomainPtr dom = domain_get(s);
-    int vcpus;
-
-    vcpus = virDomainGetMaxVcpus(dom);
-    _E(vcpus < 0, create_error(e_RetrieveError, "virDomainGetMaxVcpus", "", conn(s)));
-
-    return INT2NUM(vcpus);
-}
-
-
-/*
- * Call +virDomainSetVcpus+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetVcpus]
- */
-VALUE libvirt_dom_vcpus_set(VALUE s, VALUE nvcpus) {
-    virDomainPtr dom = domain_get(s);
-    int r;
-
-    r = virDomainSetVcpus(dom, NUM2UINT(nvcpus));
-    _E(r < 0, create_error(e_DefinitionError, "virDomainSetVcpus", "", conn(s)));
-
-    return r;
-}
-
-/*
- * Call +virDomainPinVcpu+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainPinVcpu]
- */
-VALUE libvirt_dom_pin_vcpu(VALUE s, VALUE vcpu, VALUE cpulist) {
-    virDomainPtr dom = domain_get(s);
-    int r, i, len, maplen;
-    unsigned char *cpumap;
-    virNodeInfo nodeinfo;
-    virConnectPtr c = conn(s);
-
-    r = virNodeGetInfo(c, &nodeinfo);
-    _E(r < 0, create_error(e_RetrieveError, "virNodeGetInfo", "", c));
-
-    maplen = VIR_CPU_MAPLEN(nodeinfo.cpus);
-    cpumap = ALLOC_N(unsigned char, maplen);
-    MEMZERO(cpumap, unsigned char, maplen);
-
-    len = RARRAY(cpulist)->len;
-    for(i = 0; i < len; i++) {
-        VALUE e = rb_ary_entry(cpulist, i);
-        VIR_USE_CPU(cpumap, NUM2UINT(e));
-    }
-
-    r = virDomainPinVcpu(dom, NUM2UINT(vcpu), cpumap, maplen);
-    free(cpumap);
-    _E(r < 0, create_error(e_RetrieveError, "virDomainPinVcpu", "", c));
-
-    return r;
-}
-
-
-/*
- * Call +virDomainGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetXMLDesc]
- */
-VALUE libvirt_dom_xml_desc(int argc, VALUE *argv, VALUE s) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    gen_call_string(virDomainGetXMLDesc, conn(s), 1,
-                    domain_get(s), 0);
-}
-
-/*
- * Call +virDomainUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainUndefine]
- */
-VALUE libvirt_dom_undefine(VALUE s) {
-    gen_call_void(virDomainUndefine, conn(s),
-                  domain_get(s));
-}
-
-/*
- * Call +virDomainCreate+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCreate]
- */
-VALUE libvirt_dom_create(VALUE s) {
-    gen_call_void(virDomainCreate, conn(s),
-                  domain_get(s));
-}
-
-/*
- * Call +virDomainGetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetAutostart]
- */
-VALUE libvirt_dom_autostart(VALUE s){
-    virDomainPtr dom = domain_get(s);
-    int r, autostart;
-
-    r = virDomainGetAutostart(dom, &autostart);
-    _E(r < 0, create_error(e_RetrieveError, "virDomainAutostart", "", conn(s)));
-
-    return autostart ? Qtrue : Qfalse;
-}
-
-/*
- * Call +virDomainSetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetAutostart]
- */
-VALUE libvirt_dom_autostart_set(VALUE s, VALUE autostart) {
-    gen_call_void(virDomainSetAutostart, conn(s),
-                  domain_get(s), RTEST(autostart) ? 1 : 0);
-}
-
-/*
- * Call +virDomainCreateLinux+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCreateLinux]
- */
-VALUE libvirt_conn_create_linux(int argc, VALUE *argv, VALUE c) {
-    virDomainPtr dom;
-    virConnectPtr conn = connect_get(c);
-    char *xmlDesc;
-    VALUE flags, xml;
-
-    rb_scan_args(argc, argv, "11", &xml, &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    xmlDesc = StringValueCStr(xml);
-
-    dom = virDomainCreateLinux(conn, xmlDesc, NUM2UINT(flags));
-    _E(dom == NULL, create_error(e_Error, "virDomainCreateLinux", "", conn));
-
-    return domain_new(dom, c);
-}
-
-/*
- * Call +virDomainLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainLookupByName]
- */
-VALUE libvirt_conn_lookup_domain_by_name(VALUE c, VALUE name) {
-    virDomainPtr dom;
-    virConnectPtr conn = connect_get(c);
-
-    dom = virDomainLookupByName(conn, StringValueCStr(name));
-    _E(dom == NULL, create_error(e_RetrieveError, "virDomainLookupByName", "", conn));
-
-    return domain_new(dom, c);
-}
-
-/*
- * Call +virDomainLookupByID+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainLookupByID]
- */
-VALUE libvirt_conn_lookup_domain_by_id(VALUE c, VALUE id) {
-    virDomainPtr dom;
-    virConnectPtr conn = connect_get(c);
-
-    dom = virDomainLookupByID(conn, NUM2INT(id));
-    _E(dom == NULL, create_error(e_RetrieveError, "virDomainLookupByID", "", conn));
-
-    return domain_new(dom, c);
-}
-
-/*
- * Call +virDomainLookupByUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainLookupByUUIDString]
- */
-VALUE libvirt_conn_lookup_domain_by_uuid(VALUE c, VALUE uuid) {
-    virDomainPtr dom;
-    virConnectPtr conn = connect_get(c);
-
-    dom = virDomainLookupByUUIDString(conn, StringValueCStr(uuid));
-    _E(dom == NULL, create_error(e_RetrieveError, "virDomainLookupByUUID", "", conn));
-
-    return domain_new(dom, c);
-}
-
-/*
- * Call +virDomainDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainDefineXML]
- */
-VALUE libvirt_conn_define_domain_xml(VALUE c, VALUE xml) {
-    virDomainPtr dom;
-    virConnectPtr conn = connect_get(c);
-
-    dom = virDomainDefineXML(conn, StringValueCStr(xml));
-    _E(dom == NULL, create_error(e_DefinitionError, "virDomainDefineXML", "", conn));
-
-    return domain_new(dom, c);
-}
-
-/*
- * Call +virDomainFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainFree]
- */
-VALUE libvirt_dom_free(VALUE s) {
-    gen_call_free(Domain, s);
-}
-
-/*
- * Class Libvirt::Network
- */
-
-#if HAVE_TYPE_VIRNETWORKPTR
-/*
- * Call +virNetworkLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkLookupByName]
- */
-VALUE libvirt_conn_lookup_network_by_name(VALUE c, VALUE name) {
-    virNetworkPtr netw;
-    virConnectPtr conn = connect_get(c);
-
-    netw = virNetworkLookupByName(conn, StringValueCStr(name));
-    _E(netw == NULL, create_error(e_RetrieveError, "virNetworkLookupByName", "", conn));
-
-    return network_new(netw, c);
-}
-
-/*
- * Call +virNetworkLookupByUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkLookupByUUIDString]
- */
-VALUE libvirt_conn_lookup_network_by_uuid(VALUE c, VALUE uuid) {
-    virNetworkPtr netw;
-    virConnectPtr conn = connect_get(c);
-
-    netw = virNetworkLookupByUUIDString(conn, StringValueCStr(uuid));
-    _E(netw == NULL, create_error(e_RetrieveError, "virNetworkLookupByUUID", "", conn));
-
-    return network_new(netw, c);
-}
-
-/*
- * Call +virNetworkCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkCreateXML]
- */
-VALUE libvirt_conn_create_network_xml(VALUE c, VALUE xml) {
-    virNetworkPtr netw;
-    virConnectPtr conn = connect_get(c);
-    char *xmlDesc;
-
-    xmlDesc = StringValueCStr(xml);
-
-    netw = virNetworkCreateXML(conn, xmlDesc);
-    _E(netw == NULL, create_error(e_Error, "virNetworkCreateXML", "", conn));
-
-    return network_new(netw, c);
-}
-
-/*
- * Call +virNetworkDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkDefineXML]
- */
-VALUE libvirt_conn_define_network_xml(VALUE c, VALUE xml) {
-    virNetworkPtr netw;
-    virConnectPtr conn = connect_get(c);
-
-    netw = virNetworkDefineXML(conn, StringValueCStr(xml));
-    _E(netw == NULL, create_error(e_DefinitionError, "virNetworkDefineXML", "", conn));
-
-    return network_new(netw, c);
-}
-#endif
-
-#if HAVE_TYPE_VIRNETWORKPTR
-/*
- * Call +virNetworkUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkUndefine]
- */
-VALUE libvirt_netw_undefine(VALUE s) {
-    gen_call_void(virNetworkUndefine, conn(s),
-                  network_get(s));
-}
-
-/*
- * Call +virNetworkCreate+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkCreate]
- */
-VALUE libvirt_netw_create(VALUE s) {
-    gen_call_void(virNetworkCreate, conn(s),
-                  network_get(s));
-}
-
-/*
- * Call +virNetworkDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkDestroy]
- */
-VALUE libvirt_netw_destroy(VALUE s) {
-    gen_call_void(virNetworkDestroy, conn(s),
-                  network_get(s));
-}
-
-/*
- * Call +virNetworkGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetName]
- */
-VALUE libvirt_netw_name(VALUE s) {
-    gen_call_string(virNetworkGetName, conn(s), 0,
-                    network_get(s));
-}
-
-/*
- * Call +virNetworkGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetUUIDString]
- */
-VALUE libvirt_netw_uuid(VALUE s) {
-    virNetworkPtr netw = network_get(s);
-    char uuid[VIR_UUID_STRING_BUFLEN];
-    int r;
-
-    r = virNetworkGetUUIDString(netw, uuid);
-    _E(r < 0, create_error(e_RetrieveError, "virNetworkGetUUIDString", "", conn(s)));
-
-    return rb_str_new2((char *) uuid);
-}
-
-/*
- * Call +virNetworkGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetXMLDesc]
- */
-VALUE libvirt_netw_xml_desc(int argc, VALUE *argv, VALUE s) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    gen_call_string(virNetworkGetXMLDesc, conn(s), 1,
-                    network_get(s), NUM2UINT(flags));
-}
-
-/*
- * Call +virNetworkGetBridgeName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetBridgeName]
- */
-VALUE libvirt_netw_bridge_name(VALUE s) {
-    gen_call_string(virNetworkGetBridgeName, conn(s), 1,
-                    network_get(s));
-}
-
-/*
- * Call +virNetworkGetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetAutostart]
- */
-VALUE libvirt_netw_autostart(VALUE s){
-    virNetworkPtr netw = network_get(s);
-    int r, autostart;
-
-    r = virNetworkGetAutostart(netw, &autostart);
-    _E(r < 0, create_error(e_RetrieveError, "virNetworkAutostart", "", conn(s)));
-
-    return autostart ? Qtrue : Qfalse;
-}
-
-/*
- * Call +virNetworkSetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkSetAutostart]
- */
-VALUE libvirt_netw_autostart_set(VALUE s, VALUE autostart) {
-    gen_call_void(virNetworkSetAutostart, conn(s),
-                  network_get(s), RTEST(autostart) ? 1 : 0);
-}
-
-/*
- * Call +virNetworkFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkFree]
- */
-VALUE libvirt_netw_free(VALUE s) {
-    gen_call_free(Network, s);
-}
-#endif
-
-/*
- * Libvirt::StoragePool
- */
-
-#if HAVE_TYPE_VIRSTORAGEPOOLPTR
-/*
- * Call +virStoragePoolLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolLookupByName]
- */
-VALUE libvirt_conn_lookup_pool_by_name(VALUE c, VALUE name) {
-    virStoragePoolPtr pool;
-    virConnectPtr conn = connect_get(c);
-
-    pool = virStoragePoolLookupByName(conn, StringValueCStr(name));
-    _E(pool == NULL, create_error(e_RetrieveError, "virStoragePoolLookupByName", "", conn));
-
-    return pool_new(pool, c);
-}
-
-/*
- * Call +virStoragePoolLookupByUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolLookupByUUIDString]
- */
-VALUE libvirt_conn_lookup_pool_by_uuid(VALUE c, VALUE uuid) {
-    virStoragePoolPtr pool;
-    virConnectPtr conn = connect_get(c);
-
-    pool = virStoragePoolLookupByUUIDString(conn, StringValueCStr(uuid));
-    _E(pool == NULL, create_error(e_RetrieveError, "virStoragePoolLookupByUUID", "", conn));
-
-    return pool_new(pool, c);
-}
-
-/*
- * Call +virStoragePoolLookupByVolume+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolLookupByVolume]
- */
-VALUE libvirt_vol_get_pool(VALUE v) {
-    virStoragePoolPtr pool;
-
-    pool = virStoragePoolLookupByVolume(vol_get(v));
-    _E(pool == NULL, create_error(e_RetrieveError, "virStoragePoolLookupByVolume", "", conn(v)));
-
-    return pool_new(pool, conn_attr(v));
-}
-
-/*
- * Call +virStoragePoolCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolCreateXML]
- */
-VALUE libvirt_conn_create_pool_xml(int argc, VALUE *argv, VALUE c) {
-    virStoragePoolPtr pool;
-    virConnectPtr conn = connect_get(c);
-    char *xmlDesc;
-    VALUE xml, flags;
-
-    rb_scan_args(argc, argv, "11", &xml, &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    xmlDesc = StringValueCStr(xml);
-
-    pool = virStoragePoolCreateXML(conn, xmlDesc, NUM2UINT(flags));
-    _E(pool == NULL, create_error(e_Error, "virStoragePoolCreateXML", "", conn));
-
-    return pool_new(pool, c);
-}
-
-/*
- * Call +virStoragePoolDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolDefineXML]
- */
-VALUE libvirt_conn_define_pool_xml(int argc, VALUE *argv, VALUE c) {
-    virStoragePoolPtr pool;
-    virConnectPtr conn = connect_get(c);
-    VALUE xml, flags;
-
-    rb_scan_args(argc, argv, "11", &xml, &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    pool = virStoragePoolDefineXML(conn, StringValueCStr(xml), NUM2UINT(flags));
-    _E(pool == NULL, create_error(e_DefinitionError, "virStoragePoolDefineXML", "", conn));
-
-    return pool_new(pool, c);
-}
-
-/*
- * Call +virStoragePoolBuild+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolBuild]
- */
-VALUE libvirt_pool_build(int argc, VALUE *argv, VALUE p) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
+static VALUE c_libvirt_version;
 
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
+VALUE m_libvirt;
 
-    gen_call_void(virStoragePoolBuild, conn(p),
-                  pool_get(p), NUM2UINT(flags));
-}
+/* define additional errors here */
+static VALUE e_ConnectionError;         /* ConnectionError - error during connection establishment */
+VALUE e_DefinitionError;
+VALUE e_RetrieveError;
+VALUE e_Error;
+VALUE e_NoSupportError;
 
-/*
- * Call +virStoragePoolUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolUndefine]
- */
-VALUE libvirt_pool_undefine(VALUE p) {
-    gen_call_void(virStoragePoolUndefine, conn(p),
-                  pool_get(p));
+/* custom error function to suppress libvirt printing to stderr */
+static void rubyLibvirtErrorFunc(void *userdata, virErrorPtr err){
 }
 
 /*
- * Call +virStoragePoolCreate+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolCreate]
+ * call-seq:
+ *   Libvirt::version(type=nil) -> [ libvirt_version, type_version ]
+ *
+ * Call
+ * +virGetVersion+[http://www.libvirt.org/html/libvirt-libvirt.html#virGetVersion]
+ * to get the version of libvirt and of the hypervisor TYPE.
  */
-VALUE libvirt_pool_create(int argc, VALUE *argv, VALUE p) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
+static VALUE libvirt_version(int argc, VALUE *argv, VALUE m) {
+    unsigned long libVer;
+    VALUE type;
+    unsigned long typeVer;
+    int r;
+    VALUE result, rargv[2];
 
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
+    rb_scan_args(argc, argv, "01", &type);
 
-    gen_call_void(virStoragePoolCreate, conn(p),
-                  pool_get(p), NUM2UINT(flags));
-}
+    r = virGetVersion(&libVer, get_string_or_nil(type), &typeVer);
+    _E(r < 0, create_error(rb_eArgError, "virGetVersion", NULL));
 
-/*
- * Call +virStoragePoolDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolDestroy]
- */
-VALUE libvirt_pool_destroy(VALUE p) {
-    gen_call_void(virStoragePoolDestroy, conn(p),
-                  pool_get(p));
+    result = rb_ary_new2(2);
+    rargv[0] = rb_str_new2("libvirt");
+    rargv[1] = ULONG2NUM(libVer);
+    rb_ary_push(result, rb_class_new_instance(2, rargv, c_libvirt_version));
+    rargv[0] = type;
+    rargv[1] = ULONG2NUM(typeVer);
+    rb_ary_push(result, rb_class_new_instance(2, rargv, c_libvirt_version));
+    return result;
 }
 
-/*
- * Call +virStoragePoolDelete+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolDelete]
- */
-VALUE libvirt_pool_delete(int argc, VALUE *argv, VALUE p) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
+static VALUE internal_open(int argc, VALUE *argv, VALUE m, int readonly)
+{
+    VALUE uri;
+    char *uri_c;
+    virConnectPtr conn;
 
-    gen_call_void(virStoragePoolDelete, conn(p),
-                  pool_get(p), NUM2UINT(flags));
-}
+    rb_scan_args(argc, argv, "01", &uri);
 
-/*
- * Call +virStoragePoolRefresh+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolRefresh]
- */
-VALUE libvirt_pool_refresh(int argc, VALUE *argv, VALUE p) {
-    VALUE flags;
+    uri_c = get_string_or_nil(uri);
 
-    rb_scan_args(argc, argv, "01", &flags);
+    if (readonly)
+        conn = virConnectOpenReadOnly(uri_c);
+    else
+        conn = virConnectOpen(uri_c);
 
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
+    _E(conn == NULL, create_error(e_ConnectionError,
+                                  readonly ? "virConnectOpenReadOnly" : "virConnectOpen",
+                                  NULL));
 
-    gen_call_void(virStoragePoolRefresh, conn(p),
-                  pool_get(p), NUM2UINT(flags));
+    return connect_new(conn);
 }
 
 /*
- * Call +virStoragePoolGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetName]
+ * call-seq:
+ *   Libvirt::open(uri=nil) -> Libvirt::Connect
+ *
+ * Call
+ * +virConnectOpen+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpen]
+ * to open a connection to a URL.
  */
-VALUE libvirt_pool_name(VALUE s) {
-    const char *name;
-
-    name = virStoragePoolGetName(pool_get(s));
-    _E(name == NULL, create_error(e_RetrieveError, "virStoragePoolGetName", "", conn(s)));
-
-    return rb_str_new2(name);
+static VALUE libvirt_open(int argc, VALUE *argv, VALUE m) {
+    return internal_open(argc, argv, m, 0);
 }
 
 /*
- * Call +virStoragePoolGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetUUIDString]
+ * call-seq:
+ *   Libvirt::open_read_only(uri=nil) -> Libvirt::Connect
+ *
+ * Call
+ * +virConnectOpenReadOnly+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpenReadOnly]
+ * to open a read-only connection to a URL.
  */
-VALUE libvirt_pool_uuid(VALUE s) {
-    char uuid[VIR_UUID_STRING_BUFLEN];
-    int r;
-
-    r = virStoragePoolGetUUIDString(pool_get(s), uuid);
-    _E(r < 0, create_error(e_RetrieveError, "virStoragePoolGetUUIDString", "", conn(s)));
-
-    return rb_str_new2((char *) uuid);
+static VALUE libvirt_open_read_only(int argc, VALUE *argv, VALUE m) {
+    return internal_open(argc, argv, m, 1);
 }
 
-/*
- * Call +virStoragePoolGetInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetInfo]
- */
-VALUE libvirt_pool_info(VALUE s) {
-    virStoragePoolInfo info;
-    int r;
+#if HAVE_VIRCONNECTOPENAUTH
+static int libvirt_auth_callback_wrapper(virConnectCredentialPtr cred,
+                                         unsigned int ncred, void *cbdata) {
+    VALUE userdata;
+    VALUE newcred;
+    int i;
     VALUE result;
 
-    r = virStoragePoolGetInfo(pool_get(s), &info);
-    _E(r < 0, create_error(e_RetrieveError, "virStoragePoolGetInfo", "", conn(s)));
-
-    result = rb_class_new_instance(0, NULL, c_storage_pool_info);
-    rb_iv_set(result, "@state", INT2FIX(info.state));
-    rb_iv_set(result, "@capacity", ULL2NUM(info.capacity));
-    rb_iv_set(result, "@allocation", ULL2NUM(info.allocation));
-    rb_iv_set(result, "@available", ULL2NUM(info.available));
+    userdata = (VALUE)cbdata;
+
+    if (!rb_block_given_p())
+        rb_raise(rb_eRuntimeError, "No block given, this should never happen!\n");
+
+    for (i = 0; i < ncred; i++) {
+        newcred = rb_hash_new();
+
+        rb_hash_aset(newcred, rb_str_new2("type"), INT2NUM(cred[i].type));
+        rb_hash_aset(newcred, rb_str_new2("prompt"),
+                     rb_str_new2(cred[i].prompt));
+        if (cred[i].challenge)
+            rb_hash_aset(newcred, rb_str_new2("challenge"),
+                         rb_str_new2(cred[i].challenge));
+        else
+            rb_hash_aset(newcred, rb_str_new2("challenge"), Qnil);
+        if (cred[i].defresult)
+            rb_hash_aset(newcred, rb_str_new2("defresult"),
+                         rb_str_new2(cred[i].defresult));
+        else
+            rb_hash_aset(newcred, rb_str_new2("defresult"), Qnil);
+        rb_hash_aset(newcred, rb_str_new2("result"), Qnil);
+        rb_hash_aset(newcred, rb_str_new2("userdata"), userdata);
+
+        result = rb_yield(newcred);
+        if (NIL_P(result)) {
+            cred[i].result = NULL;
+            cred[i].resultlen = 0;
+        }
+        else {
+            cred[i].result = strdup(StringValueCStr(result));
+            cred[i].resultlen = strlen(cred[i].result);
+        }
+    }
 
-    return result;
+    return 0;
 }
 
-/*
- * Call +virStoragePoolGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetXMLDesc]
- */
-VALUE libvirt_pool_xml_desc(int argc, VALUE *argv, VALUE s) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
 
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    gen_call_string(virStoragePoolGetXMLDesc, conn(s), 1,
-                    pool_get(s), NUM2UINT(flags));
-}
-
-/*
- * Call +virStoragePoolGetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetAutostart]
- */
-VALUE libvirt_pool_autostart(VALUE s){
-    int r, autostart;
+struct wrap_callout {
+    char *uri;
+    virConnectAuthPtr auth;
+    unsigned int flags;
+};
 
-    r = virStoragePoolGetAutostart(pool_get(s), &autostart);
-    _E(r < 0, create_error(e_RetrieveError, "virStoragePoolGetAutostart", "", conn(s)));
+static VALUE rb_open_auth_wrap(VALUE arg) {
+    struct wrap_callout *e = (struct wrap_callout *)arg;
 
-    return autostart ? Qtrue : Qfalse;
+    return (VALUE)virConnectOpenAuth(e->uri, e->auth, e->flags);
 }
 
-/*
- * Call +virStoragePoolSetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolSetAutostart]
- */
-VALUE libvirt_pool_autostart_set(VALUE s, VALUE autostart) {
-    gen_call_void(virStoragePoolSetAutostart, conn(s),
-                  pool_get(s), RTEST(autostart) ? 1 : 0);
+static VALUE rb_num2int_wrap(VALUE arg) {
+    return NUM2INT(arg);
 }
 
 /*
- * Call +virStoragePoolNumOfVolumes+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolNumOfVolumes]
- */
-VALUE libvirt_pool_num_of_volumes(VALUE s) {
-    int n = virStoragePoolNumOfVolumes(pool_get(s));
-    _E(n < 0, create_error(e_RetrieveError, "virStoragePoolNumOfVolumes", "", conn(s)));
-
-    return INT2FIX(n);
-}
+ * call-seq:
+ *   Libvirt::open_auth(uri=nil, credlist=nil, userdata=nil, flags=0) {|...| authentication block} -> Libvirt::Connect
+ *
+ * Call
+ * +virConnectOpenAuth+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpenAuth]
+ * to open a connection to a libvirt URI, with a possible authentication block.
+ * If an authentication block is desired, then credlist should be an array that
+ * specifies which credentials the authentication block is willing to support;
+ * the full list is available at http://libvirt.org/html/libvirt-libvirt.html#virConnectCredentialType.
+ * If userdata is not nil and an authentication block is given, userdata will
+ * be passed unaltered into the authentication block.  The flags parameter
+ * controls how to open connection.  The only options currently available for
+ * flags are 0 for a read/write connection and Libvirt::CONNECT_RO for a
+ * read-only connection.
+ *
+ * If the credlist is not empty, and an authentication block is given, the
+ * authentication block will be called once for each credential necessary
+ * to complete the authentication.  The authentication block will be passed a
+ * single parameter, which is a hash of values containing information necessary
+ * to complete authentication.  This hash contains 5 elements:
+ *
+ * type - the type of credential to be examined
+ *
+ * prompt - a suggested prompt to show to the user
+ *
+ * challenge - any additional challenge information
+ *
+ * defresult - a default result to use if credentials could not be obtained
+ *
+ * userdata - the userdata passed into open_auth initially
+ *
+ * The authentication block should return the result of collecting the
+ * information; these results will then be sent to libvirt for authentication.
+ */
+static VALUE libvirt_open_auth(int argc, VALUE *argv, VALUE m) {
+    virConnectAuthPtr auth;
+    VALUE uri;
+    VALUE credlist;
+    VALUE userdata;
+    VALUE flags_val;
+    char *uri_c;
+    virConnectPtr conn = NULL;
+    unsigned int flags;
+    int auth_alloc;
+    int i;
+    VALUE tmp;
+    int exception = 0;
+    struct rb_ary_entry_arg args;
+    struct wrap_callout callargs;
+
+    rb_scan_args(argc, argv, "04", &uri, &credlist, &userdata, &flags_val);
+
+    /* handle the optional URI */
+    uri_c = get_string_or_nil(uri);
+
+    /* handle the optional flags */
+    if (NIL_P(flags_val))
+        flags = 0;
+    else
+        flags = NUM2UINT(flags_val);
+
+    if (rb_block_given_p()) {
+        auth = ALLOC(virConnectAuth);
+        auth_alloc = 1;
+
+        if (TYPE(credlist) == T_NIL)
+            auth->ncredtype = 0;
+        else if (TYPE(credlist) == T_ARRAY)
+            auth->ncredtype = RARRAY_LEN(credlist);
+        else
+            rb_raise(rb_eTypeError, "wrong argument type (expected Array or nil)");
+        auth->credtype = NULL;
+        if (auth->ncredtype > 0) {
+            /* we don't use ALLOC_N here because that can throw an exception,
+             * and leak the auth pointer.  Instead we use normal malloc
+             * (which has a slightly higher chance of returning NULL), and
+             * then properly cleanup if it fails
+             */
+            auth->credtype = malloc(sizeof(int) * auth->ncredtype);
+            if (auth->credtype == NULL) {
+                xfree(auth);
+                rb_memerror();
+            }
+            for (i = 0; i < auth->ncredtype; i++) {
+                args.arr = credlist;
+                args.elem = i;
+                tmp = rb_protect(rb_ary_entry_wrap, (VALUE)&args, &exception);
+                if (exception)
+                    goto do_cleanup;
+
+                auth->credtype[i] = rb_protect(rb_num2int_wrap, tmp,
+                                               &exception);
+                if (exception)
+                    goto do_cleanup;
+            }
+        }
+
+        auth->cb = libvirt_auth_callback_wrapper;
+        auth->cbdata = (void *)userdata;
+    }
+    else {
+        auth = virConnectAuthPtrDefault;
+        auth_alloc = 0;
+    }
 
-/*
- * Call +virStoragePoolListVolumes+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolListVolumes]
- */
-VALUE libvirt_pool_list_volumes(VALUE s) {
-    int i, r, num;
-    char **names;
-    virStoragePoolPtr pool = pool_get(s);
-    VALUE result;
+    callargs.uri = uri_c;
+    callargs.auth = auth;
+    callargs.flags = flags;
 
-    num = virStoragePoolNumOfVolumes(pool);
-    _E(num < 0, create_error(e_RetrieveError, "virStoragePoolNumOfVolumes", "", conn(s)));
+    conn = (virConnectPtr)rb_protect(rb_open_auth_wrap, (VALUE)&callargs,
+                                     &exception);
 
-    names = ALLOC_N(char *, num);
-    r = virStoragePoolListVolumes(pool, names, num);
-    if (r < 0) {
-        free(names);
-        _E(r < 0, create_error(e_RetrieveError, "virStoragePoolListVolumes", "", conn(s)));
+do_cleanup:
+    if (auth_alloc) {
+        free(auth->credtype);
+        xfree(auth);
     }
 
-    result = rb_ary_new2(num);
-    for (i=0; i<num; i++) {
-        rb_ary_push(result, rb_str_new2(names[i]));
-        // FIXME: Should these really be freed ?
-        free(names[i]);
-    }
-    free(names);
-    return result;
-}
+    if (exception)
+        rb_jump_tag(exception);
 
-/*
- * Call +virStoragePoolFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolFree]
- */
-VALUE libvirt_pool_free(VALUE s) {
-    gen_call_free(StoragePool, s);
+    _E(conn == NULL, create_error(e_ConnectionError, "virConnectOpenAuth",
+                                  NULL));
+
+    return connect_new(conn);
 }
 #endif
 
+#if HAVE_VIREVENTREGISTERIMPL
+static VALUE add_handle, update_handle, remove_handle;
+static VALUE add_timeout, update_timeout, remove_timeout;
+
 /*
- * Libvirt::StorageVol
- */
-#if HAVE_TYPE_VIRSTORAGEVOLPTR
-/*
- * Call +virStorageVolLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByName]
- */
-VALUE libvirt_pool_lookup_vol_by_name(VALUE p, VALUE name) {
-    virStorageVolPtr vol;
+ * call-seq:
+ *   Libvirt::event_invoke_handle_callback(handle, fd, events, opaque) -> Qnil
+ *
+ * Unlike most of the other functions in the ruby-libvirt bindings, this one
+ * does not directly correspond to a libvirt API function.  Instead, this
+ * module method (and event_invoke_timeout_callback) are meant to be called
+ * when there is an event of interest to libvirt on one of the file descriptors
+ * that libvirt uses.  The application is notified of the file descriptors
+ * that libvirt uses via the callbacks from Libvirt::event_register_impl.  When
+ * there is an event of interest, the application must call
+ * event_invoke_timeout_callback to ensure proper operation.
+ *
+ * Libvirt::event_invoke_handle_callback takes 4 arguments:
+ *
+ * handle
+ *          an application specific handle ID.  This can be any integer, but
+ *          must be unique from all other libvirt handles in the application.
+ * fd
+ *          the file descriptor of interest.  This was given to the application
+ *          as a callback to add_handle of Libvirt::event_register_impl
+ * events
+ *          the events that have occured on the fd.  Note that the events are
+ *          libvirt specific, and are some combination of
+ *          Libvirt::EVENT_HANDLE_READABLE, Libvirt::EVENT_HANDLE_WRITABLE,
+ *          Libvirt::EVENT_HANDLE_ERROR, Libvirt::EVENT_HANDLE_HANGUP.  To
+ *          notify libvirt of more than one event at a time, these values should
+ *          be logically OR'ed together.
+ * opaque
+ *          the opaque data passed from libvirt during the
+ *          Libvirt::event_register_impl add_handle callback.  To ensure proper
+ *          operation this data must be passed through to
+ *          event_invoke_handle_callback without modification.
+ */
+static VALUE libvirt_event_invoke_handle_callback(VALUE m, VALUE handle,
+                                                  VALUE fd, VALUE events,
+                                                  VALUE opaque) {
+    virEventHandleCallback cb;
+    void *op;
+    VALUE libvirt_cb;
+    VALUE libvirt_opaque;
+
+    if (TYPE(opaque) != T_HASH)
+        rb_raise(rb_eTypeError,
+                 "wrong event callback argument type (expected Hash)");
+
+    libvirt_cb = rb_hash_aref(opaque, rb_str_new2("libvirt_cb"));
+
+    /* This is equivalent to Data_Get_Struct; I reproduce it here because
+     * I don't want the additional type-cast that Data_Get_Struct does
+     */
+    Check_Type(libvirt_cb, T_DATA);
+    cb = DATA_PTR(libvirt_cb);
 
-    vol = virStorageVolLookupByName(pool_get(p), StringValueCStr(name));
-    _E(vol == NULL, create_error(e_RetrieveError, "virStorageVolLookupByName", "", conn(p)));
+    if (cb) {
+        libvirt_opaque = rb_hash_aref(opaque, rb_str_new2("opaque"));
+        Data_Get_Struct(libvirt_opaque, void *, op);
+        cb(NUM2INT(handle), NUM2INT(fd), NUM2INT(events), op);
+    }
 
-    return vol_new(vol, conn_attr(p));
+    return Qnil;
 }
 
 /*
- * Call +virStorageVolLookupByKey+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByKey]
- */
-VALUE libvirt_pool_lookup_vol_by_key(VALUE p, VALUE key) {
-    virStorageVolPtr vol;
+ * call-seq:
+ *   Libvirt::event_invoke_timeout_callback(timer, opaque) -> Qnil
+ *
+ * Unlike most of the other functions in the ruby-libvirt bindings, this one
+ * does not directly correspond to a libvirt API function.  Instead, this
+ * module method (and event_invoke_handle_callback) are meant to be called
+ * when there is a timeout of interest to libvirt.  The application is
+ * notified of the timers that libvirt uses via the callbacks from
+ * Libvirt::event_register_impl.  When a timeout expires, the application must
+ * call event_invoke_timeout_callback to ensure proper operation.
+ *
+ * Libvirt::event_invoke_timeout_callback takes 2 arguments:
+ *
+ * handle
+ *          an application specific timer ID.  This can be any integer, but
+ *          must be unique from all other libvirt timers in the application.
+ * opaque
+ *          the opaque data passed from libvirt during the
+ *          Libvirt::event_register_impl add_handle callback.  To ensure proper
+ *          operation this data must be passed through to
+ *          event_invoke_handle_callback without modification.
+ */
+static VALUE libvirt_event_invoke_timeout_callback(VALUE m, VALUE timer,
+                                                   VALUE opaque) {
+    virEventTimeoutCallback cb;
+    void *op;
+    VALUE libvirt_cb;
+    VALUE libvirt_opaque;
+
+    if (TYPE(opaque) != T_HASH)
+        rb_raise(rb_eTypeError,
+                 "wrong event callback argument type (expected Hash)");
+
+    libvirt_cb = rb_hash_aref(opaque, rb_str_new2("libvirt_cb"));
+
+    /* This is equivalent to Data_Get_Struct; I reproduce it here because
+     * I don't want the additional type-cast that Data_Get_Struct does
+     */
+    Check_Type(libvirt_cb, T_DATA);
+    cb = DATA_PTR(libvirt_cb);
 
-    // FIXME: Why does this take a connection, not a pool ?
-    vol = virStorageVolLookupByKey(conn(p), StringValueCStr(key));
-    _E(vol == NULL, create_error(e_RetrieveError, "virStorageVolLookupByKey", "", conn(p)));
+    if (cb) {
+        libvirt_opaque = rb_hash_aref(opaque, rb_str_new2("opaque"));
+        Data_Get_Struct(libvirt_opaque, void *, op);
+        cb(NUM2INT(timer), op);
+    }
 
-    return vol_new(vol, conn_attr(p));
+    return Qnil;
 }
 
-/*
- * Call +virStorageVolLookupByPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByPath]
- */
-VALUE libvirt_pool_lookup_vol_by_path(VALUE p, VALUE path) {
-    virStorageVolPtr vol;
+static int internal_add_handle_func(int fd, int events,
+                                    virEventHandleCallback cb, void *opaque,
+                                    virFreeCallback ff) {
+    VALUE rubyargs;
+    VALUE res;
+
+    rubyargs = rb_hash_new();
+    rb_hash_aset(rubyargs, rb_str_new2("libvirt_cb"),
+                 Data_Wrap_Struct(rb_class_of(add_handle), NULL, NULL, cb));
+    rb_hash_aset(rubyargs, rb_str_new2("opaque"),
+                 Data_Wrap_Struct(rb_class_of(add_handle), NULL, NULL, opaque));
+    rb_hash_aset(rubyargs, rb_str_new2("free_func"),
+                 Data_Wrap_Struct(rb_class_of(add_handle), NULL, NULL, ff));
+
+    /* call out to the ruby object */
+    if (strcmp(rb_obj_classname(add_handle), "Symbol") == 0)
+        res = rb_funcall(rb_class_of(add_handle), rb_to_id(add_handle), 3,
+                         INT2NUM(fd), INT2NUM(events), rubyargs);
+    else if (strcmp(rb_obj_classname(add_handle), "Proc") == 0)
+        res = rb_funcall(add_handle, rb_intern("call"), 3, INT2NUM(fd),
+                         INT2NUM(events), rubyargs);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong add handle callback argument type (expected Symbol or Proc)");
 
-    // FIXME: Why does this take a connection, not a pool ?
-    vol = virStorageVolLookupByPath(conn(p), StringValueCStr(path));
-    _E(vol == NULL, create_error(e_RetrieveError, "virStorageVolLookupByPath", "", conn(p)));
+    if (TYPE(res) != T_FIXNUM)
+        rb_raise(rb_eTypeError,
+                 "expected integer return from add_handle callback");
 
-    return vol_new(vol, conn_attr(p));
+    return NUM2INT(res);
 }
 
-/*
- * Call +virStorageVolGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetName]
- */
-VALUE libvirt_vol_name(VALUE v) {
-    gen_call_string(virStorageVolGetName, conn(v), 0,
-                    vol_get(v));
-}
+static void internal_update_handle_func(int watch, int event) {
+    /* call out to the ruby object */
+    if (strcmp(rb_obj_classname(update_handle), "Symbol") == 0)
+        rb_funcall(rb_class_of(update_handle), rb_to_id(update_handle), 2,
+                   INT2NUM(watch), INT2NUM(event));
+    else if (strcmp(rb_obj_classname(update_handle), "Proc") == 0)
+        rb_funcall(update_handle, rb_intern("call"), 2, INT2NUM(watch),
+                   INT2NUM(event));
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong update handle callback argument type (expected Symbol or Proc)");
+}
+
+static int internal_remove_handle_func(int watch) {
+    VALUE res;
+    virFreeCallback ff_cb;
+    void *op;
+    VALUE libvirt_opaque;
+    VALUE ff;
+
+    /* call out to the ruby object */
+    if (strcmp(rb_obj_classname(remove_handle), "Symbol") == 0)
+        res = rb_funcall(rb_class_of(remove_handle), rb_to_id(remove_handle),
+                         1, INT2NUM(watch));
+    else if (strcmp(rb_obj_classname(remove_handle), "Proc") == 0)
+        res = rb_funcall(remove_handle, rb_intern("call"), 1, INT2NUM(watch));
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong remove handle callback argument type (expected Symbol or Proc)");
+
+    if (TYPE(res) != T_HASH)
+        rb_raise(rb_eTypeError,
+                 "expected opaque hash returned from remove_handle callback");
+
+    ff = rb_hash_aref(res, rb_str_new2("free_func"));
+    if (!NIL_P(ff)) {
+        /* This is equivalent to Data_Get_Struct; I reproduce it here because
+         * I don't want the additional type-cast that Data_Get_Struct does
+         */
+        Check_Type(ff, T_DATA);
+        ff_cb = DATA_PTR(ff);
+        if (ff_cb) {
+            libvirt_opaque = rb_hash_aref(res, rb_str_new2("opaque"));
+            Data_Get_Struct(libvirt_opaque, void *, op);
+
+            (*ff_cb)(op);
+        }
+    }
 
-/*
- * Call +virStorageVolGetKey+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetKey]
- */
-VALUE libvirt_vol_key(VALUE v) {
-    gen_call_string(virStorageVolGetKey, conn(v), 0,
-                    vol_get(v));
+    return 0;
 }
 
-/*
- * Call +virStorageVolCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolCreateXML]
- */
-VALUE libvirt_pool_vol_create_xml(int argc, VALUE *argv, VALUE p) {
-    virStorageVolPtr vol;
-    virConnectPtr c = conn(p);
-    char *xmlDesc;
-    VALUE xml, flags;
-
-    rb_scan_args(argc, argv, "11", &xml, &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    xmlDesc = StringValueCStr(xml);
+static int internal_add_timeout_func(int interval, virEventTimeoutCallback cb,
+                                     void *opaque, virFreeCallback ff) {
+    VALUE rubyargs;
+    VALUE res;
 
-    vol = virStorageVolCreateXML(pool_get(p), xmlDesc, NUM2UINT(flags));
-    _E(vol == NULL, create_error(e_Error, "virNetworkCreateXML", "", c));
+    rubyargs = rb_hash_new();
 
-    return vol_new(vol, conn_attr(p));
-}
-
-/*
- * Call +virStorageVolDelete+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolDelete]
- */
-VALUE libvirt_vol_delete(int argc, VALUE *argv, VALUE v) {
-    VALUE flags;
+    rb_hash_aset(rubyargs, rb_str_new2("libvirt_cb"),
+                 Data_Wrap_Struct(rb_class_of(add_timeout), NULL, NULL, cb));
+    rb_hash_aset(rubyargs, rb_str_new2("opaque"),
+                 Data_Wrap_Struct(rb_class_of(add_timeout), NULL, NULL,
+                                  opaque));
+    rb_hash_aset(rubyargs, rb_str_new2("free_func"),
+                 Data_Wrap_Struct(rb_class_of(add_timeout), NULL, NULL, ff));
 
-    rb_scan_args(argc, argv, "01", &flags);
+    /* call out to the ruby object */
+    if (strcmp(rb_obj_classname(add_timeout), "Symbol") == 0)
+        res = rb_funcall(rb_class_of(add_timeout), rb_to_id(add_timeout), 2,
+                         INT2NUM(interval), rubyargs);
+    else if (strcmp(rb_obj_classname(add_timeout), "Proc") == 0)
+        res = rb_funcall(add_timeout, rb_intern("call"), 2, INT2NUM(interval),
+                         rubyargs);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong add timeout callback argument type (expected Symbol or Proc)");
 
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
+    if (TYPE(res) != T_FIXNUM)
+        rb_raise(rb_eTypeError,
+                 "expected integer return from add_timeout callback");
 
-    gen_call_void(virStorageVolDelete, conn(v),
-                  vol_get(v), NUM2UINT(flags));
+    return NUM2INT(res);
 }
 
-/*
- * Call +virStorageVolGetInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetInfo]
- */
-VALUE libvirt_vol_info(VALUE v) {
-    virStorageVolInfo info;
-    int r;
-    VALUE result;
-
-    r = virStorageVolGetInfo(vol_get(v), &info);
-    _E(r < 0, create_error(e_RetrieveError, "virStorageVolGetInfo", "", conn(v)));
-
-    result = rb_class_new_instance(0, NULL, c_storage_vol_info);
-    rb_iv_set(result, "@type", INT2NUM(info.type));
-    rb_iv_set(result, "@capacity", ULL2NUM(info.capacity));
-    rb_iv_set(result, "@allocation", ULL2NUM(info.allocation));
+static void internal_update_timeout_func(int timer, int timeout) {
+    /* call out to the ruby object */
+    if (strcmp(rb_obj_classname(update_timeout), "Symbol") == 0)
+        rb_funcall(rb_class_of(update_timeout), rb_to_id(update_timeout), 2,
+                   INT2NUM(timer), INT2NUM(timeout));
+    else if (strcmp(rb_obj_classname(update_timeout), "Proc") == 0)
+        rb_funcall(update_timeout, rb_intern("call"), 2, INT2NUM(timer),
+                   INT2NUM(timeout));
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong update timeout callback argument type (expected Symbol or Proc)");
+}
+
+static int internal_remove_timeout_func(int timer) {
+    VALUE res;
+    virFreeCallback ff_cb;
+    void *op;
+    VALUE libvirt_opaque;
+    VALUE ff;
+
+    /* call out to the ruby object */
+    if (strcmp(rb_obj_classname(remove_timeout), "Symbol") == 0)
+        res = rb_funcall(rb_class_of(remove_timeout), rb_to_id(remove_timeout),
+                         1, INT2NUM(timer));
+    else if (strcmp(rb_obj_classname(remove_timeout), "Proc") == 0)
+        res = rb_funcall(remove_timeout, rb_intern("call"), 1, INT2NUM(timer));
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong remove timeout callback argument type (expected Symbol or Proc)");
+
+    if (TYPE(res) != T_HASH)
+        rb_raise(rb_eTypeError,
+                 "expected opaque hash returned from remove_timeout callback");
+
+    ff = rb_hash_aref(res, rb_str_new2("free_func"));
+    if (!NIL_P(ff)) {
+        /* This is equivalent to Data_Get_Struct; I reproduce it here because
+         * I don't want the additional type-cast that Data_Get_Struct does
+         */
+        Check_Type(ff, T_DATA);
+        ff_cb = DATA_PTR(ff);
+        if (ff_cb) {
+            libvirt_opaque = rb_hash_aref(res, rb_str_new2("opaque"));
+            Data_Get_Struct(libvirt_opaque, void *, op);
+
+            (*ff_cb)(op);
+        }
+    }
 
-    return result;
+    return 0;
 }
 
-/*
- * Call +virStorageVolGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetXMLDesc]
- */
-VALUE libvirt_vol_xml_desc(int argc, VALUE *argv, VALUE v) {
-    VALUE flags;
-
-    rb_scan_args(argc, argv, "01", &flags);
-
-    if (NIL_P(flags))
-        flags = INT2FIX(0);
-
-    gen_call_string(virStorageVolGetXMLDesc, conn(v), 1,
-                    vol_get(v), NUM2UINT(flags));
-}
+#define set_event_func_or_null(type)                \
+    do {                                            \
+        if (NIL_P(type))                            \
+            type##_temp = NULL;                     \
+        else                                        \
+            type##_temp = internal_##type##_func;   \
+    } while(0)
 
-/*
- * Call +virStorageVolGetPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetPath]
- */
-VALUE libvirt_vol_path(VALUE v) {
-    gen_call_string(virStorageVolGetPath, conn(v), 1,
-                    vol_get(v));
+static int is_symbol_proc_or_nil(VALUE handle) {
+    if (NIL_P(handle))
+        return 1;
+    return is_symbol_or_proc(handle);
 }
 
 /*
- * Call +virStorageVolFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolFree]
- */
-VALUE libvirt_vol_free(VALUE s) {
-    gen_call_free(StorageVol, s);
-}
-#endif
+ * call-seq:
+ *   Libvirt::event_register_impl(add_handle=nil, update_handle=nil, remove_handle=nil, add_timeout=nil, update_timeout=nil, remove_timeout=nil) -> Qnil
+ *
+ * Call
+ * +virEventRegisterImpl+[http://www.libvirt.org/html/libvirt-libvirt.html#virEventRegisterImpl]
+ * to register callback handlers for handles and timeouts.  These handles and
+ * timeouts are used as part of the libvirt infrastructure for generating
+ * domain events.  Each callback must be a Symbol (that is the name of a
+ * method to callback), a Proc, or nil (to disable the callback).  In the
+ * end-user application program, these callbacks are typically used to track
+ * the file descriptors or timers that libvirt is interested in (and is intended
+ * to be integrated into the "main loop" of a UI program).  The individual
+ * callbacks will be given a certain number of arguments, and must return
+ * certain values.  Those arguments and return types are:
+ *
+ * add_handle(fd, events, opaque) => Fixnum
+ *
+ * update_handle(handleID, event) => nil
+ *
+ * remove_handle(handleID) => opaque data from add_handle
+ *
+ * add_timeout(interval, opaque) => Fixnum
+ *
+ * update_timeout(timerID, timeout) => nil
+ *
+ * remove_timeout(timerID) => opaque data from add_timeout
+ *
+ * Any arguments marked as "opaque" must be accepted from the library and saved
+ * without modification.  The values passed to the callbacks are meant to be
+ * passed to the event_invoke_handle_callback and event_invoke_timeout_callback
+ * module methods; see the documentation for those methods for more details.
+ */
+static VALUE libvirt_conn_event_register_impl(int argc, VALUE *argv, VALUE c) {
+    virEventAddHandleFunc add_handle_temp;
+    virEventUpdateHandleFunc update_handle_temp;
+    virEventRemoveHandleFunc remove_handle_temp;
+    virEventAddTimeoutFunc add_timeout_temp;
+    virEventUpdateTimeoutFunc update_timeout_temp;
+    virEventRemoveTimeoutFunc remove_timeout_temp;
 
-static void init_storage(void) {
     /*
-     * Class Libvirt::StoragePool and Libvirt::StoragePoolInfo
+     * subtle; we put the arguments (callbacks) directly into the global
+     * add_handle, update_handle, etc. variables.  Then we register the
+     * internal functions as the callbacks with virEventRegisterImpl
      */
-#if HAVE_TYPE_VIRSTORAGEPOOLPTR
-    c_storage_pool_info = rb_define_class_under(m_libvirt, "StoragePoolInfo",
-                                                rb_cObject);
-    rb_define_attr(c_storage_pool_info, "state", 1, 0);
-    rb_define_attr(c_storage_pool_info, "capacity", 1, 0);
-    rb_define_attr(c_storage_pool_info, "allocation", 1, 0);
-    rb_define_attr(c_storage_pool_info, "available", 1, 0);
-
-    c_storage_pool = rb_define_class_under(m_libvirt, "StoragePool", 
-                                           rb_cObject);
-#define DEF_POOLCONST(name)                                        \
-    rb_define_const(c_storage_pool, #name, INT2NUM(VIR_STORAGE_POOL_##name))
-    /* virStoragePoolState */
-    DEF_POOLCONST(INACTIVE);
-    DEF_POOLCONST(BUILDING);
-    DEF_POOLCONST(RUNNING);
-    DEF_POOLCONST(DEGRADED);
-    /* virStoragePoolBuildFlags */
-    DEF_POOLCONST(BUILD_NEW);
-    DEF_POOLCONST(BUILD_REPAIR);
-    DEF_POOLCONST(BUILD_RESIZE);
-    /* virStoragePoolDeleteFlags */
-    DEF_POOLCONST(DELETE_NORMAL);
-    DEF_POOLCONST(DELETE_ZEROED);
-#undef DEF_POOLCONST
-    /* Creating/destroying pools */
-    rb_define_method(c_storage_pool, "build", libvirt_pool_build, -1);
-    rb_define_method(c_storage_pool, "undefine", libvirt_pool_undefine, 0);
-    rb_define_method(c_storage_pool, "create", libvirt_pool_create, -1);
-    rb_define_method(c_storage_pool, "destroy", libvirt_pool_destroy, 0);
-    rb_define_method(c_storage_pool, "delete", libvirt_pool_delete, -1);
-    rb_define_method(c_storage_pool, "refresh", libvirt_pool_refresh, -1);
-    /* StoragePool information */
-    rb_define_method(c_storage_pool, "name", libvirt_pool_name, 0);
-    rb_define_method(c_storage_pool, "uuid", libvirt_pool_uuid, 0);
-    rb_define_method(c_storage_pool, "info", libvirt_pool_info, 0);
-    rb_define_method(c_storage_pool, "xml_desc", libvirt_pool_xml_desc, -1);
-    rb_define_method(c_storage_pool, "autostart", libvirt_pool_autostart, 0);
-    rb_define_method(c_storage_pool, "autostart=",
-                     libvirt_pool_autostart_set, 1);
-    /* List/lookup storage volumes within a pool */
-    rb_define_method(c_storage_pool, "num_of_volumes",
-                     libvirt_pool_num_of_volumes, 0);
-    rb_define_method(c_storage_pool, "list_volumes",
-                     libvirt_pool_list_volumes, 0);
-    /* Lookup volumes based on various attributes */
-    rb_define_method(c_storage_pool, "lookup_volume_by_name",
-                     libvirt_pool_lookup_vol_by_name, 1);
-    rb_define_method(c_storage_pool, "lookup_volume_by_key",
-                     libvirt_pool_lookup_vol_by_key, 1);
-    rb_define_method(c_storage_pool, "lookup_volume_by_path",
-                     libvirt_pool_lookup_vol_by_path, 1);
-    rb_define_method(c_storage_pool, "free", libvirt_pool_free, 0);
-    rb_define_method(c_storage_pool, "create_vol_xml", libvirt_pool_vol_create_xml, -1);
-#endif
+    rb_scan_args(argc, argv, "06", &add_handle, &update_handle, &remove_handle,
+                 &add_timeout, &update_timeout, &remove_timeout);
+
+    if (!is_symbol_proc_or_nil(add_handle) ||
+        !is_symbol_proc_or_nil(update_handle) ||
+        !is_symbol_proc_or_nil(remove_handle) ||
+        !is_symbol_proc_or_nil(add_timeout) ||
+        !is_symbol_proc_or_nil(update_timeout) ||
+        !is_symbol_proc_or_nil(remove_timeout))
+        rb_raise(rb_eTypeError,
+                 "wrong argument type (expected Symbol, Proc, or nil)");
+
+    set_event_func_or_null(add_handle);
+    set_event_func_or_null(update_handle);
+    set_event_func_or_null(remove_handle);
+    set_event_func_or_null(add_timeout);
+    set_event_func_or_null(update_timeout);
+    set_event_func_or_null(remove_timeout);
+
+    /* virEventRegisterImpl returns void, so no error checking here */
+    virEventRegisterImpl(add_handle_temp, update_handle_temp,
+                         remove_handle_temp, add_timeout_temp,
+                         update_timeout_temp, remove_timeout_temp);
 
-#if HAVE_TYPE_VIRSTORAGEVOLPTR
-    /*
-     * Class Libvirt::StorageVol and Libvirt::StorageVolInfo
-     */
-    c_storage_vol_info = rb_define_class_under(m_libvirt, "StorageVolInfo",
-                                               rb_cObject);
-    rb_define_attr(c_storage_vol_info, "type", 1, 0);
-    rb_define_attr(c_storage_vol_info, "capacity", 1, 0);
-    rb_define_attr(c_storage_vol_info, "allocation", 1, 0);
-
-    c_storage_vol = rb_define_class_under(m_libvirt, "StorageVol",
-                                          rb_cObject);
-#define DEF_VOLCONST(name)                                        \
-    rb_define_const(c_storage_vol, #name, INT2NUM(VIR_STORAGE_VOL_##name))
-    /* virStorageVolType */
-    DEF_VOLCONST(FILE);
-    DEF_VOLCONST(BLOCK);
-    /* virStorageVolDeleteFlags */
-    DEF_VOLCONST(DELETE_NORMAL);
-    DEF_VOLCONST(DELETE_ZEROED);
-#undef DEF_VOLCONST
-
-    rb_define_method(c_storage_vol, "pool", libvirt_vol_get_pool, 0);
-    rb_define_method(c_storage_vol, "name", libvirt_vol_name, 0);
-    rb_define_method(c_storage_vol, "key", libvirt_vol_key, 0);
-    rb_define_method(c_storage_vol, "delete", libvirt_vol_delete, -1);
-    rb_define_method(c_storage_vol, "info", libvirt_vol_info, 0);
-    rb_define_method(c_storage_vol, "xml_desc", libvirt_vol_xml_desc, -1);
-    rb_define_method(c_storage_vol, "path", libvirt_vol_path, 0);
-    rb_define_method(c_storage_vol, "free", libvirt_vol_free, 0);
-#endif
+    return Qnil;
 }
+#endif
 
+/*
+ * Module Libvirt
+ */
 void Init__libvirt() {
-    int r;
-
     m_libvirt = rb_define_module("Libvirt");
     c_libvirt_version = rb_define_class_under(m_libvirt, "Version",
                                               rb_cObject);
 
+#if HAVE_VIRCONNECTOPENAUTH
+    rb_define_const(m_libvirt, "CONNECT_RO", INT2NUM(VIR_CONNECT_RO));
+
+    rb_define_const(m_libvirt, "CRED_USERNAME", INT2NUM(VIR_CRED_USERNAME));
+    rb_define_const(m_libvirt, "CRED_AUTHNAME", INT2NUM(VIR_CRED_AUTHNAME));
+    rb_define_const(m_libvirt, "CRED_LANGUAGE", INT2NUM(VIR_CRED_LANGUAGE));
+    rb_define_const(m_libvirt, "CRED_CNONCE", INT2NUM(VIR_CRED_CNONCE));
+    rb_define_const(m_libvirt, "CRED_PASSPHRASE", INT2NUM(VIR_CRED_PASSPHRASE));
+    rb_define_const(m_libvirt, "CRED_ECHOPROMPT", INT2NUM(VIR_CRED_ECHOPROMPT));
+    rb_define_const(m_libvirt, "CRED_NOECHOPROMPT", INT2NUM(VIR_CRED_NOECHOPROMPT));
+    rb_define_const(m_libvirt, "CRED_REALM", INT2NUM(VIR_CRED_REALM));
+    rb_define_const(m_libvirt, "CRED_EXTERNAL", INT2NUM(VIR_CRED_EXTERNAL));
+#endif
 
     /*
      * Libvirt Errors
      */
-    e_Error =           rb_define_class_under(m_libvirt, "Error", 
-                                               rb_eStandardError);
-    e_ConnectionError = rb_define_class_under(m_libvirt, "ConnectionError", 
-                                                e_Error);
-    e_DefinitionError = rb_define_class_under(m_libvirt, "DefinitionError", 
-                                                e_Error);
-    e_RetrieveError =   rb_define_class_under(m_libvirt, "RetrieveError", 
-                                                e_Error);
-
-    // create 'libvirt_function_name' and 'vir_connect_ptr' attributes on e_Error class
+    e_Error =           rb_define_class_under(m_libvirt, "Error",
+                                              rb_eStandardError);
+    e_ConnectionError = rb_define_class_under(m_libvirt, "ConnectionError",
+                                              e_Error);
+    e_DefinitionError = rb_define_class_under(m_libvirt, "DefinitionError",
+                                              e_Error);
+    e_RetrieveError =   rb_define_class_under(m_libvirt, "RetrieveError",
+                                              e_Error);
+    e_NoSupportError =  rb_define_class_under(m_libvirt, "NoSupportError",
+                                              e_Error);
+
     rb_define_attr(e_Error, "libvirt_function_name", 1, 0);
     rb_define_attr(e_Error, "libvirt_message", 1, 0);
-
-    /*
-     * Class Libvirt::Connect
-     */
-    c_connect = rb_define_class_under(m_libvirt, "Connect", rb_cObject);
-
-    rb_define_module_function(m_libvirt, "version", libvirt_version, 1);
-	rb_define_module_function(m_libvirt, "open", libvirt_open, 1);
-	rb_define_module_function(m_libvirt, "open_read_only",
-                              libvirt_open_read_only, 1);
-
-    rb_define_method(c_connect, "close", libvirt_conn_close, 0);
-    rb_define_method(c_connect, "closed?", libvirt_conn_closed_p, 0);
-    rb_define_method(c_connect, "type", libvirt_conn_type, 0);
-    rb_define_method(c_connect, "version", libvirt_conn_version, 0);
-    rb_define_method(c_connect, "hostname", libvirt_conn_hostname, 0);
-    rb_define_method(c_connect, "uri", libvirt_conn_uri, 0);
-    rb_define_method(c_connect, "max_vcpus", libvirt_conn_max_vcpus, 1);
-    rb_define_method(c_connect, "node_get_info", libvirt_conn_node_get_info, 0);
-    rb_define_method(c_connect, "capabilities", libvirt_conn_capabilities, 0);
-    rb_define_method(c_connect, "num_of_domains", libvirt_conn_num_of_domains, 0);
-    rb_define_method(c_connect, "list_domains", libvirt_conn_list_domains, 0);
-    rb_define_method(c_connect, "num_of_defined_domains",
-                     libvirt_conn_num_of_defined_domains, 0);
-    rb_define_method(c_connect, "list_defined_domains",
-                     libvirt_conn_list_defined_domains, 0);
-#if HAVE_TYPE_VIRNETWORKPTR
-    rb_define_method(c_connect, "num_of_networks",
-                     libvirt_conn_num_of_networks, 0);
-    rb_define_method(c_connect, "list_networks", libvirt_conn_list_networks, 0);
-    rb_define_method(c_connect, "num_of_defined_networks",
-                     libvirt_conn_num_of_defined_networks, 0);
-    rb_define_method(c_connect, "list_defined_networks",
-                     libvirt_conn_list_defined_networks, 0);
+    rb_define_attr(e_Error, "libvirt_code", 1, 0);
+    rb_define_attr(e_Error, "libvirt_component", 1, 0);
+    rb_define_attr(e_Error, "libvirt_level", 1, 0);
+
+    /* libvirt error components (domains) */
+    rb_define_const(e_Error, "FROM_NONE", INT2NUM(VIR_FROM_NONE));
+    rb_define_const(e_Error, "FROM_XEN", INT2NUM(VIR_FROM_XEN));
+    rb_define_const(e_Error, "FROM_XEND", INT2NUM(VIR_FROM_XEND));
+    rb_define_const(e_Error, "FROM_XENSTORE", INT2NUM(VIR_FROM_XENSTORE));
+    rb_define_const(e_Error, "FROM_SEXPR", INT2NUM(VIR_FROM_SEXPR));
+    rb_define_const(e_Error, "FROM_XML", INT2NUM(VIR_FROM_XML));
+    rb_define_const(e_Error, "FROM_DOM", INT2NUM(VIR_FROM_DOM));
+    rb_define_const(e_Error, "FROM_RPC", INT2NUM(VIR_FROM_RPC));
+    rb_define_const(e_Error, "FROM_PROXY", INT2NUM(VIR_FROM_PROXY));
+    rb_define_const(e_Error, "FROM_CONF", INT2NUM(VIR_FROM_CONF));
+    rb_define_const(e_Error, "FROM_QEMU", INT2NUM(VIR_FROM_QEMU));
+    rb_define_const(e_Error, "FROM_NET", INT2NUM(VIR_FROM_NET));
+    rb_define_const(e_Error, "FROM_TEST", INT2NUM(VIR_FROM_TEST));
+    rb_define_const(e_Error, "FROM_REMOTE", INT2NUM(VIR_FROM_REMOTE));
+    rb_define_const(e_Error, "FROM_OPENVZ", INT2NUM(VIR_FROM_OPENVZ));
+#if HAVE_CONST_VIR_FROM_VMWARE
+    rb_define_const(e_Error, "FROM_VMWARE", INT2NUM(VIR_FROM_VMWARE));
 #endif
-#if HAVE_TYPE_VIRSTORAGEPOOLPTR
-    rb_define_method(c_connect, "num_of_storage_pools",
-                     libvirt_conn_num_of_storage_pools, 0);
-    rb_define_method(c_connect, "list_storage_pools",
-                     libvirt_conn_list_storage_pools, 0);
-    rb_define_method(c_connect, "num_of_defined_storage_pools",
-                     libvirt_conn_num_of_defined_storage_pools, 0);
-    rb_define_method(c_connect, "list_defined_storage_pools",
-                     libvirt_conn_list_defined_storage_pools, 0);
+#if HAVE_CONST_VIR_FROM_XENXM
+    rb_define_const(e_Error, "FROM_XENXM", INT2NUM(VIR_FROM_XENXM));
+#endif
+#if HAVE_CONST_VIR_FROM_STATS_LINUX
+    rb_define_const(e_Error, "FROM_STATS_LINUX", INT2NUM(VIR_FROM_STATS_LINUX));
 #endif
-    // Domain creation/lookup
-    rb_define_method(c_connect, "create_domain_linux",
-                     libvirt_conn_create_linux, -1);
-    rb_define_method(c_connect, "lookup_domain_by_name",
-                     libvirt_conn_lookup_domain_by_name, 1);
-    rb_define_method(c_connect, "lookup_domain_by_id",
-                     libvirt_conn_lookup_domain_by_id, 1);
-    rb_define_method(c_connect, "lookup_domain_by_uuid",
-                     libvirt_conn_lookup_domain_by_uuid, 1);
-    rb_define_method(c_connect, "define_domain_xml",
-                     libvirt_conn_define_domain_xml, 1);
-    // Network creation/lookup
-#if HAVE_TYPE_VIRNETWORKPTR
-    rb_define_method(c_connect, "lookup_network_by_name",
-                     libvirt_conn_lookup_network_by_name, 1);
-    rb_define_method(c_connect, "lookup_network_by_uuid",
-                     libvirt_conn_lookup_network_by_uuid, 1);
-    rb_define_method(c_connect, "create_network_xml",
-                     libvirt_conn_create_network_xml, 1);
-    rb_define_method(c_connect, "define_network_xml",
-                     libvirt_conn_define_network_xml, 1);
+#if HAVE_TYPE_VIR_FROM_LXC
+    rb_define_const(e_Error, "FROM_LXC", INT2NUM(VIR_FROM_LXC));
 #endif
-    // Storage pool creation/lookup
 #if HAVE_TYPE_VIRSTORAGEPOOLPTR
-    rb_define_method(c_connect, "lookup_storage_pool_by_name",
-                     libvirt_conn_lookup_pool_by_name, 1);
-    rb_define_method(c_connect, "lookup_storage_pool_by_uuid",
-                     libvirt_conn_lookup_pool_by_uuid, 1);
-    rb_define_method(c_connect, "create_storage_pool_xml",
-                     libvirt_conn_create_pool_xml, -1);
-    rb_define_method(c_connect, "define_storage_pool_xml",
-                     libvirt_conn_define_pool_xml, -1);
+    rb_define_const(e_Error, "FROM_STORAGE", INT2NUM(VIR_FROM_STORAGE));
+#endif
+#if HAVE_CONST_VIR_FROM_NETWORK
+    rb_define_const(e_Error, "FROM_NETWORK", INT2NUM(VIR_FROM_NETWORK));
+#endif
+#if HAVE_CONST_VIR_FROM_DOMAIN
+    rb_define_const(e_Error, "FROM_DOMAIN", INT2NUM(VIR_FROM_DOMAIN));
+#endif
+#if HAVE_CONST_VIR_FROM_UML
+    rb_define_const(e_Error, "FROM_UML", INT2NUM(VIR_FROM_UML));
+#endif
+#if HAVE_TYPE_VIRNODEDEVICEPTR
+    rb_define_const(e_Error, "FROM_NODEDEV", INT2NUM(VIR_FROM_NODEDEV));
+#endif
+#if HAVE_CONST_VIR_FROM_XEN_INOTIFY
+    rb_define_const(e_Error, "FROM_XEN_INOTIFY", INT2NUM(VIR_FROM_XEN_INOTIFY));
+#endif
+#if HAVE_CONST_VIR_FROM_SECURITY
+    rb_define_const(e_Error, "FROM_SECURITY", INT2NUM(VIR_FROM_SECURITY));
+#endif
+#if HAVE_CONST_VIR_FROM_VBOX
+    rb_define_const(e_Error, "FROM_VBOX", INT2NUM(VIR_FROM_VBOX));
+#endif
+#if HAVE_TYPE_VIRINTERFACEPTR
+    rb_define_const(e_Error, "FROM_INTERFACE", INT2NUM(VIR_FROM_INTERFACE));
+#endif
+#if HAVE_CONST_VIR_FROM_ONE
+    rb_define_const(e_Error, "FROM_ONE", INT2NUM(VIR_FROM_ONE));
+#endif
+#if HAVE_CONST_VIR_FROM_ESX
+    rb_define_const(e_Error, "FROM_ESX", INT2NUM(VIR_FROM_ESX));
+#endif
+#if HAVE_CONST_VIR_FROM_PHYP
+    rb_define_const(e_Error, "FROM_PHYP", INT2NUM(VIR_FROM_PHYP));
+#endif
+#if HAVE_TYPE_VIRSECRETPTR
+    rb_define_const(e_Error, "FROM_SECRET", INT2NUM(VIR_FROM_SECRET));
+#endif
+#if HAVE_VIRCONNECTCOMPARECPU
+    rb_define_const(e_Error, "FROM_CPU", INT2NUM(VIR_FROM_CPU));
+#endif
+#if HAVE_CONST_VIR_FROM_XENAPI
+    rb_define_const(e_Error, "FROM_XENAPI", INT2NUM(VIR_FROM_XENAPI));
+#endif
+#if HAVE_TYPE_VIRNWFILTERPTR
+    rb_define_const(e_Error, "FROM_NWFILTER", INT2NUM(VIR_FROM_NWFILTER));
+#endif
+#if HAVE_CONST_VIR_FROM_HOOK
+    rb_define_const(e_Error, "FROM_HOOK", INT2NUM(VIR_FROM_HOOK));
+#endif
+#if HAVE_TYPE_VIRDOMAINSNAPSHOTPTR
+    rb_define_const(e_Error, "FROM_DOMAIN_SNAPSHOT",
+                    INT2NUM(VIR_FROM_DOMAIN_SNAPSHOT));
+#endif
+#if HAVE_CONST_VIR_FROM_AUDIT
+    rb_define_const(e_Error, "FROM_AUDIT", INT2NUM(VIR_FROM_AUDIT));
+#endif
+#if HAVE_CONST_VIR_FROM_SYSINFO
+    rb_define_const(e_Error, "FROM_SYSINFO", INT2NUM(VIR_FROM_SYSINFO));
+#endif
+#if HAVE_CONST_VIR_FROM_STREAMS
+    rb_define_const(e_Error, "FROM_STREAMS", INT2NUM(VIR_FROM_STREAMS));
 #endif
 
-    /*
-     * Class Libvirt::Connect::Nodeinfo
-     */
-    c_node_info = rb_define_class_under(c_connect, "Nodeinfo", rb_cObject);
-    rb_define_attr(c_node_info, "model", 1, 0);
-    rb_define_attr(c_node_info, "memory", 1, 0);
-    rb_define_attr(c_node_info, "cpus", 1, 0);
-    rb_define_attr(c_node_info, "mhz", 1, 0);
-    rb_define_attr(c_node_info, "nodes", 1, 0);
-    rb_define_attr(c_node_info, "sockets", 1, 0);
-    rb_define_attr(c_node_info, "cores", 1, 0);
-    rb_define_attr(c_node_info, "threads", 1, 0);
-
-    /*
-     * Class Libvirt::Domain
-     */
-    c_domain = rb_define_class_under(m_libvirt, "Domain", rb_cObject);
-#define DEF_DOMSTATE(name) \
-    rb_define_const(c_domain, #name, INT2NUM(VIR_DOMAIN_##name))
-    /* virDomainState */
-    DEF_DOMSTATE(NOSTATE);
-    DEF_DOMSTATE(RUNNING);
-    DEF_DOMSTATE(BLOCKED);
-    DEF_DOMSTATE(PAUSED);
-    DEF_DOMSTATE(SHUTDOWN);
-    DEF_DOMSTATE(SHUTOFF);
-    DEF_DOMSTATE(CRASHED);
-#undef DEF_DOMSTATE
-
-    rb_define_method(c_domain, "migrate", libvirt_dom_migrate, 5);
-    rb_define_attr(c_domain, "connection", 1, 0);
-    rb_define_method(c_domain, "shutdown", libvirt_dom_shutdown, 0);
-    rb_define_method(c_domain, "reboot", libvirt_dom_reboot, -1);
-    rb_define_method(c_domain, "destroy", libvirt_dom_destroy, 0);
-    rb_define_method(c_domain, "suspend", libvirt_dom_suspend, 0);
-    rb_define_method(c_domain, "resume", libvirt_dom_resume, 0);
-    rb_define_method(c_domain, "save", libvirt_dom_save, 1);
-    rb_define_singleton_method(c_domain, "restore", libvirt_dom_s_restore, 2);
-    rb_define_method(c_domain, "core_dump", libvirt_dom_core_dump, -1);
-    rb_define_method(c_domain, "info", libvirt_dom_info, 0);
-    rb_define_method(c_domain, "name", libvirt_dom_name, 0);
-    rb_define_method(c_domain, "id", libvirt_dom_id, 0);
-    rb_define_method(c_domain, "uuid", libvirt_dom_uuid, 0);
-    rb_define_method(c_domain, "os_type", libvirt_dom_os_type, 0);
-    rb_define_method(c_domain, "max_memory", libvirt_dom_max_memory, 0);
-    rb_define_method(c_domain, "max_memory=", libvirt_dom_max_memory_set, 1);
-    rb_define_method(c_domain, "memory=", libvirt_dom_memory_set, 1);
-    rb_define_method(c_domain, "max_vcpus", libvirt_dom_max_vcpus, 0);
-    rb_define_method(c_domain, "vcpus=", libvirt_dom_vcpus_set, 1);
-    rb_define_method(c_domain, "pin_vcpu", libvirt_dom_pin_vcpu, 2);
-    rb_define_method(c_domain, "xml_desc", libvirt_dom_xml_desc, -1);
-    rb_define_method(c_domain, "undefine", libvirt_dom_undefine, 0);
-    rb_define_method(c_domain, "create", libvirt_dom_create, 0);
-    rb_define_method(c_domain, "autostart", libvirt_dom_autostart, 0);
-    rb_define_method(c_domain, "autostart=", libvirt_dom_autostart_set, 1);
-    rb_define_method(c_domain, "free", libvirt_dom_free, 0);
+    /* libvirt error codes */
+    rb_define_const(e_Error, "ERR_OK", INT2NUM(VIR_ERR_OK));
+    rb_define_const(e_Error, "ERR_INTERNAL_ERROR",
+                    INT2NUM(VIR_ERR_INTERNAL_ERROR));
+    rb_define_const(e_Error, "ERR_NO_MEMORY", INT2NUM(VIR_ERR_NO_MEMORY));
+    rb_define_const(e_Error, "ERR_NO_SUPPORT", INT2NUM(VIR_ERR_NO_SUPPORT));
+    rb_define_const(e_Error, "ERR_UNKNOWN_HOST", INT2NUM(VIR_ERR_UNKNOWN_HOST));
+    rb_define_const(e_Error, "ERR_NO_CONNECT", INT2NUM(VIR_ERR_NO_CONNECT));
+    rb_define_const(e_Error, "ERR_INVALID_CONN", INT2NUM(VIR_ERR_INVALID_CONN));
+    rb_define_const(e_Error, "ERR_INVALID_DOMAIN",
+                    INT2NUM(VIR_ERR_INVALID_DOMAIN));
+    rb_define_const(e_Error, "ERR_INVALID_ARG", INT2NUM(VIR_ERR_INVALID_ARG));
+    rb_define_const(e_Error, "ERR_OPERATION_FAILED",
+                    INT2NUM(VIR_ERR_OPERATION_FAILED));
+    rb_define_const(e_Error, "ERR_GET_FAILED", INT2NUM(VIR_ERR_GET_FAILED));
+    rb_define_const(e_Error, "ERR_POST_FAILED", INT2NUM(VIR_ERR_POST_FAILED));
+    rb_define_const(e_Error, "ERR_HTTP_ERROR", INT2NUM(VIR_ERR_HTTP_ERROR));
+    rb_define_const(e_Error, "ERR_SEXPR_SERIAL", INT2NUM(VIR_ERR_SEXPR_SERIAL));
+    rb_define_const(e_Error, "ERR_NO_XEN", INT2NUM(VIR_ERR_NO_XEN));
+    rb_define_const(e_Error, "ERR_XEN_CALL", INT2NUM(VIR_ERR_XEN_CALL));
+    rb_define_const(e_Error, "ERR_OS_TYPE", INT2NUM(VIR_ERR_OS_TYPE));
+    rb_define_const(e_Error, "ERR_NO_KERNEL", INT2NUM(VIR_ERR_NO_KERNEL));
+    rb_define_const(e_Error, "ERR_NO_ROOT", INT2NUM(VIR_ERR_NO_ROOT));
+    rb_define_const(e_Error, "ERR_NO_SOURCE", INT2NUM(VIR_ERR_NO_SOURCE));
+    rb_define_const(e_Error, "ERR_NO_TARGET", INT2NUM(VIR_ERR_NO_TARGET));
+    rb_define_const(e_Error, "ERR_NO_NAME", INT2NUM(VIR_ERR_NO_NAME));
+    rb_define_const(e_Error, "ERR_NO_OS", INT2NUM(VIR_ERR_NO_OS));
+    rb_define_const(e_Error, "ERR_NO_DEVICE", INT2NUM(VIR_ERR_NO_DEVICE));
+    rb_define_const(e_Error, "ERR_NO_XENSTORE", INT2NUM(VIR_ERR_NO_XENSTORE));
+    rb_define_const(e_Error, "ERR_DRIVER_FULL", INT2NUM(VIR_ERR_DRIVER_FULL));
+    rb_define_const(e_Error, "ERR_CALL_FAILED", INT2NUM(VIR_ERR_CALL_FAILED));
+    rb_define_const(e_Error, "ERR_XML_ERROR", INT2NUM(VIR_ERR_XML_ERROR));
+    rb_define_const(e_Error, "ERR_DOM_EXIST", INT2NUM(VIR_ERR_DOM_EXIST));
+    rb_define_const(e_Error, "ERR_OPERATION_DENIED",
+                    INT2NUM(VIR_ERR_OPERATION_DENIED));
+    rb_define_const(e_Error, "ERR_OPEN_FAILED", INT2NUM(VIR_ERR_OPEN_FAILED));
+    rb_define_const(e_Error, "ERR_READ_FAILED", INT2NUM(VIR_ERR_READ_FAILED));
+    rb_define_const(e_Error, "ERR_PARSE_FAILED", INT2NUM(VIR_ERR_PARSE_FAILED));
+    rb_define_const(e_Error, "ERR_CONF_SYNTAX", INT2NUM(VIR_ERR_CONF_SYNTAX));
+    rb_define_const(e_Error, "ERR_WRITE_FAILED", INT2NUM(VIR_ERR_WRITE_FAILED));
+    rb_define_const(e_Error, "ERR_XML_DETAIL", INT2NUM(VIR_ERR_XML_DETAIL));
+    rb_define_const(e_Error, "ERR_INVALID_NETWORK",
+                    INT2NUM(VIR_ERR_INVALID_NETWORK));
+    rb_define_const(e_Error, "ERR_NETWORK_EXIST",
+                    INT2NUM(VIR_ERR_NETWORK_EXIST));
+    rb_define_const(e_Error, "ERR_SYSTEM_ERROR", INT2NUM(VIR_ERR_SYSTEM_ERROR));
+    rb_define_const(e_Error, "ERR_RPC", INT2NUM(VIR_ERR_RPC));
+    rb_define_const(e_Error, "ERR_GNUTLS_ERROR", INT2NUM(VIR_ERR_GNUTLS_ERROR));
+    rb_define_const(e_Error, "WAR_NO_NETWORK", INT2NUM(VIR_WAR_NO_NETWORK));
+    rb_define_const(e_Error, "ERR_NO_DOMAIN", INT2NUM(VIR_ERR_NO_DOMAIN));
+    rb_define_const(e_Error, "ERR_NO_NETWORK", INT2NUM(VIR_ERR_NO_NETWORK));
+    rb_define_const(e_Error, "ERR_INVALID_MAC", INT2NUM(VIR_ERR_INVALID_MAC));
+#if HAVE_CONST_VIR_ERR_AUTH_FAILED
+    rb_define_const(e_Error, "ERR_AUTH_FAILED", INT2NUM(VIR_ERR_AUTH_FAILED));
+#endif
+#if HAVE_TYPE_VIRSTORAGEPOOLPTR
+    rb_define_const(e_Error, "ERR_INVALID_STORAGE_POOL",
+                    INT2NUM(VIR_ERR_INVALID_STORAGE_POOL));
+    rb_define_const(e_Error, "ERR_INVALID_STORAGE_VOL",
+                    INT2NUM(VIR_ERR_INVALID_STORAGE_VOL));
+    rb_define_const(e_Error, "WAR_NO_STORAGE", INT2NUM(VIR_WAR_NO_STORAGE));
+    rb_define_const(e_Error, "ERR_NO_STORAGE_POOL",
+                    INT2NUM(VIR_ERR_NO_STORAGE_POOL));
+    rb_define_const(e_Error, "ERR_NO_STORAGE_VOL",
+                    INT2NUM(VIR_ERR_NO_STORAGE_VOL));
+#endif
+#if HAVE_TYPE_VIRNODEDEVICEPTR
+    rb_define_const(e_Error, "WAR_NO_NODE", INT2NUM(VIR_WAR_NO_NODE));
+    rb_define_const(e_Error, "ERR_INVALID_NODE_DEVICE",
+                    INT2NUM(VIR_ERR_INVALID_NODE_DEVICE));
+    rb_define_const(e_Error, "ERR_NO_NODE_DEVICE",
+                    INT2NUM(VIR_ERR_NO_NODE_DEVICE));
+#endif
+#if HAVE_CONST_VIR_ERR_NO_SECURITY_MODEL
+    rb_define_const(e_Error, "ERR_NO_SECURITY_MODEL",
+                    INT2NUM(VIR_ERR_NO_SECURITY_MODEL));
+#endif
+#if HAVE_CONST_VIR_ERR_OPERATION_INVALID
+    rb_define_const(e_Error, "ERR_OPERATION_INVALID",
+                    INT2NUM(VIR_ERR_OPERATION_INVALID));
+#endif
+#if HAVE_TYPE_VIRINTERFACEPTR
+    rb_define_const(e_Error, "WAR_NO_INTERFACE", INT2NUM(VIR_WAR_NO_INTERFACE));
+    rb_define_const(e_Error, "ERR_NO_INTERFACE", INT2NUM(VIR_ERR_NO_INTERFACE));
+    rb_define_const(e_Error, "ERR_INVALID_INTERFACE",
+                    INT2NUM(VIR_ERR_INVALID_INTERFACE));
+    rb_define_const(e_Error, "ERR_MULTIPLE_INTERFACES",
+                    INT2NUM(VIR_ERR_MULTIPLE_INTERFACES));
+#endif
+#if HAVE_TYPE_VIRNWFILTERPTR
+    rb_define_const(e_Error, "WAR_NO_NWFILTER", INT2NUM(VIR_WAR_NO_NWFILTER));
+    rb_define_const(e_Error, "ERR_INVALID_NWFILTER",
+                    INT2NUM(VIR_ERR_INVALID_NWFILTER));
+    rb_define_const(e_Error, "ERR_NO_NWFILTER", INT2NUM(VIR_ERR_NO_NWFILTER));
+    rb_define_const(e_Error, "ERR_BUILD_FIREWALL",
+                    INT2NUM(VIR_ERR_BUILD_FIREWALL));
+#endif
+#if HAVE_TYPE_VIRSECRETPTR
+    rb_define_const(e_Error, "WAR_NO_SECRET", INT2NUM(VIR_WAR_NO_SECRET));
+    rb_define_const(e_Error, "ERR_INVALID_SECRET",
+                    INT2NUM(VIR_ERR_INVALID_SECRET));
+    rb_define_const(e_Error, "ERR_NO_SECRET", INT2NUM(VIR_ERR_NO_SECRET));
+#endif
+#if HAVE_CONST_VIR_ERR_CONFIG_UNSUPPORTED
+    rb_define_const(e_Error, "ERR_CONFIG_UNSUPPORTED",
+                    INT2NUM(VIR_ERR_CONFIG_UNSUPPORTED));
+#endif
+#if HAVE_CONST_VIR_ERR_OPERATION_TIMEOUT
+    rb_define_const(e_Error, "ERR_OPERATION_TIMEOUT",
+                    INT2NUM(VIR_ERR_OPERATION_TIMEOUT));
+#endif
+#if HAVE_CONST_VIR_ERR_MIGRATE_PERSIST_FAILED
+    rb_define_const(e_Error, "ERR_MIGRATE_PERSIST_FAILED",
+                    INT2NUM(VIR_ERR_MIGRATE_PERSIST_FAILED));
+#endif
+#if HAVE_CONST_VIR_ERR_HOOK_SCRIPT_FAILED
+    rb_define_const(e_Error, "ERR_HOOK_SCRIPT_FAILED",
+                    INT2NUM(VIR_ERR_HOOK_SCRIPT_FAILED));
+#endif
+#if HAVE_TYPE_VIRDOMAINSNAPSHOTPTR
+    rb_define_const(e_Error, "ERR_INVALID_DOMAIN_SNAPSHOT",
+                    INT2NUM(VIR_ERR_INVALID_DOMAIN_SNAPSHOT));
+    rb_define_const(e_Error, "ERR_NO_DOMAIN_SNAPSHOT",
+                    INT2NUM(VIR_ERR_NO_DOMAIN_SNAPSHOT));
+#endif
 
-    /*
-     * Class Libvirt::Domain::Info
-     */
-    c_domain_info = rb_define_class_under(c_domain, "Info", rb_cObject);
-    rb_define_attr(c_domain_info, "state", 1, 0);
-    rb_define_attr(c_domain_info, "max_mem", 1, 0);
-    rb_define_attr(c_domain_info, "memory", 1, 0);
-    rb_define_attr(c_domain_info, "nr_virt_cpu", 1, 0);
-    rb_define_attr(c_domain_info, "cpu_time", 1, 0);
+    /* libvirt levels */
+    rb_define_const(e_Error, "LEVEL_NONE", INT2NUM(VIR_ERR_NONE));
+    rb_define_const(e_Error, "LEVEL_WARNING", INT2NUM(VIR_ERR_WARNING));
+    rb_define_const(e_Error, "LEVEL_ERROR", INT2NUM(VIR_ERR_ERROR));
+
+    rb_define_module_function(m_libvirt, "version", libvirt_version, -1);
+    rb_define_module_function(m_libvirt, "open", libvirt_open, -1);
+    rb_define_module_function(m_libvirt, "open_read_only",
+                              libvirt_open_read_only, -1);
+#if HAVE_VIRCONNECTOPENAUTH
+    rb_define_module_function(m_libvirt, "open_auth", libvirt_open_auth, -1);
+#endif
 
-    /*
-     * Class Libvirt::Network
-     */
-#if HAVE_TYPE_VIRNETWORKPTR
-    c_network = rb_define_class_under(m_libvirt, "Network", rb_cObject);
-    rb_define_attr(c_network, "connection", 1, 0);
-    rb_define_method(c_network, "undefine", libvirt_netw_undefine, 0);
-    rb_define_method(c_network, "create", libvirt_netw_create, 0);
-    rb_define_method(c_network, "destroy", libvirt_netw_destroy, 0);
-    rb_define_method(c_network, "name", libvirt_netw_name, 0);
-    rb_define_method(c_network, "uuid", libvirt_netw_uuid, 0);
-    rb_define_method(c_network, "xml_desc", libvirt_netw_xml_desc, -1);
-    rb_define_method(c_network, "bridge_name", libvirt_netw_bridge_name, 0);
-    rb_define_method(c_network, "autostart", libvirt_netw_autostart, 0);
-    rb_define_method(c_network, "autostart=", libvirt_netw_autostart_set, 1);
-    rb_define_method(c_network, "free", libvirt_netw_free, 0);
+#if HAVE_VIREVENTREGISTERIMPL
+    rb_define_const(m_libvirt, "EVENT_HANDLE_READABLE",
+                    INT2NUM(VIR_EVENT_HANDLE_READABLE));
+    rb_define_const(m_libvirt, "EVENT_HANDLE_WRITABLE",
+                    INT2NUM(VIR_EVENT_HANDLE_WRITABLE));
+    rb_define_const(m_libvirt, "EVENT_HANDLE_ERROR",
+                    INT2NUM(VIR_EVENT_HANDLE_ERROR));
+    rb_define_const(m_libvirt, "EVENT_HANDLE_HANGUP",
+                    INT2NUM(VIR_EVENT_HANDLE_HANGUP));
+
+    /* since we are using globals, we have to register with the gc */
+    rb_global_variable(&add_handle);
+    rb_global_variable(&update_handle);
+    rb_global_variable(&remove_handle);
+    rb_global_variable(&add_timeout);
+    rb_global_variable(&update_timeout);
+    rb_global_variable(&remove_timeout);
+
+    rb_define_module_function(m_libvirt, "event_register_impl",
+                              libvirt_conn_event_register_impl, -1);
+    rb_define_module_function(m_libvirt, "event_invoke_handle_callback",
+                              libvirt_event_invoke_handle_callback, 4);
+    rb_define_module_function(m_libvirt, "event_invoke_timeout_callback",
+                              libvirt_event_invoke_timeout_callback, 2);
 #endif
 
+    init_connect();
     init_storage();
+    init_network();
+    init_nodedevice();
+    init_secret();
+    init_nwfilter();
+    init_interface();
+    init_domain();
+    init_stream();
 
-    r = virInitialize();
-    if (r < 0)
+    virSetErrorFunc(NULL, rubyLibvirtErrorFunc);
+
+    if (virInitialize() < 0)
         rb_raise(rb_eSystemCallError, "virInitialize failed");
 }
-
-/*
- * Local variables:
- *  indent-tabs-mode: nil
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/ext/libvirt/common.c b/ext/libvirt/common.c
new file mode 100644
index 0000000..fa61056
--- /dev/null
+++ b/ext/libvirt/common.c
@@ -0,0 +1,203 @@
+/*
+ * common.c: Common utilities for the ruby libvirt bindings
+ *
+ * Copyright (C) 2007,2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <stdio.h>
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+
+struct rb_exc_new2_arg {
+    VALUE error;
+    char *msg;
+};
+
+static VALUE rb_exc_new2_wrap(VALUE arg) {
+    struct rb_exc_new2_arg *e = (struct rb_exc_new2_arg *)arg;
+
+    return rb_exc_new2(e->error, e->msg);
+}
+
+VALUE rb_ary_new2_wrap(VALUE arg) {
+    return rb_ary_new2(*((int *)arg));
+}
+
+VALUE rb_ary_push_wrap(VALUE arg) {
+    struct rb_ary_push_arg *e = (struct rb_ary_push_arg *)arg;
+
+    return rb_ary_push(e->arr, e->value);
+}
+
+VALUE rb_str_new2_wrap(VALUE arg) {
+    char **str = (char **)arg;
+
+    return rb_str_new2(*str);
+}
+
+VALUE rb_ary_entry_wrap(VALUE arg) {
+    struct rb_ary_entry_arg *e = (struct rb_ary_entry_arg *)arg;
+
+    return rb_ary_entry(e->arr, e->elem);
+}
+
+VALUE rb_ary_new_wrap(VALUE arg) {
+    return rb_ary_new();
+}
+
+VALUE rb_str_new_wrap(VALUE arg) {
+    struct rb_str_new_arg *e = (struct rb_str_new_arg *)arg;
+
+    return rb_str_new(e->val, e->size);
+}
+
+VALUE rb_iv_set_wrap(VALUE arg) {
+    struct rb_iv_set_arg *e = (struct rb_iv_set_arg *)arg;
+
+    return rb_iv_set(e->klass, e->member, e->value);
+}
+
+VALUE rb_class_new_instance_wrap(VALUE arg) {
+    struct rb_class_new_instance_arg *e = (struct rb_class_new_instance_arg *)arg;
+
+    return rb_class_new_instance(e->argc, e->argv, e->klass);
+}
+
+VALUE rb_string_value_cstr_wrap(VALUE arg) {
+    return (VALUE)rb_string_value_cstr((VALUE *)arg);
+}
+
+/* Error handling */
+VALUE create_error(VALUE error, const char* method, virConnectPtr conn) {
+    VALUE ruby_errinfo;
+    virErrorPtr err;
+    char *msg;
+    int rc;
+    struct rb_exc_new2_arg arg;
+    int exception = 0;
+
+    if (conn == NULL)
+        err = virGetLastError();
+    else
+        err = virConnGetLastError(conn);
+
+    if (err != NULL && err->message != NULL)
+        rc = asprintf(&msg, "Call to %s failed: %s", method, err->message);
+    else
+        rc = asprintf(&msg, "Call to %s failed", method);
+
+    if (rc < 0) {
+        /* there's not a whole lot we can do here; try to raise an
+         * out-of-memory message */
+        rb_memerror();
+    }
+
+    arg.error = error;
+    arg.msg = msg;
+    ruby_errinfo = rb_protect(rb_exc_new2_wrap, (VALUE)&arg, &exception);
+    free(msg);
+    if (exception)
+        rb_jump_tag(exception);
+
+    rb_iv_set(ruby_errinfo, "@libvirt_function_name", rb_str_new2(method));
+
+    if (err != NULL) {
+        rb_iv_set(ruby_errinfo, "@libvirt_code", INT2NUM(err->code));
+        rb_iv_set(ruby_errinfo, "@libvirt_component", INT2NUM(err->domain));
+        rb_iv_set(ruby_errinfo, "@libvirt_level", INT2NUM(err->level));
+        if (err->message != NULL)
+            rb_iv_set(ruby_errinfo, "@libvirt_message",
+                      rb_str_new2(err->message));
+    }
+
+    return ruby_errinfo;
+};
+
+char *get_string_or_nil(VALUE arg)
+{
+    if (TYPE(arg) == T_NIL)
+        return NULL;
+    else if (TYPE(arg) == T_STRING)
+        return StringValueCStr(arg);
+    else
+        rb_raise(rb_eTypeError, "wrong argument type (expected String or nil)");    return NULL;
+}
+
+VALUE generic_new(VALUE klass, void *ptr, VALUE conn,
+                  RUBY_DATA_FUNC free_func) {
+    VALUE result;
+    result = Data_Wrap_Struct(klass, NULL, free_func, ptr);
+    rb_iv_set(result, "@connection", conn);
+    return result;
+}
+
+int is_symbol_or_proc(VALUE handle) {
+    return ((strcmp(rb_obj_classname(handle), "Symbol") == 0) ||
+            (strcmp(rb_obj_classname(handle), "Proc") == 0));
+}
+
+/* this is an odd function, because it has massive side-effects.  The first
+ * tip that something is weird here should be the triple-starred list.
+ * The intended usage of this function is after a list has been collected
+ * from a libvirt list function, and now we want to make an array out of it.
+ * However, it is possible that the act of creating an array causes an
+ * exception, which would lead to a memory leak of the values we got from
+ * libvirt.  Therefore, this function not only wraps all of the relevant
+ * calls with rb_protect, it also frees every individual entry in list
+ * along with list itself.
+ */
+VALUE gen_list(int num, char ***list) {
+    VALUE result;
+    int exception = 0;
+    int i, j;
+    struct rb_ary_push_arg arg;
+
+    result = rb_protect(rb_ary_new2_wrap, (VALUE)&num, &exception);
+    if (exception) {
+        for (i = 0; i < num; i++)
+            free((*list)[i]);
+        xfree(*list);
+        rb_jump_tag(exception);
+    }
+    for (i = 0; i < num; i++) {
+        arg.arr = result;
+        arg.value = rb_protect(rb_str_new2_wrap, (VALUE)&((*list)[i]),
+                               &exception);
+        if (exception) {
+            for (j = i; j < num; j++)
+                xfree((*list)[j]);
+            xfree(*list);
+            rb_jump_tag(exception);
+        }
+        rb_protect(rb_ary_push_wrap, (VALUE)&arg, &exception);
+        if (exception) {
+            for (j = i; j < num; j++)
+                xfree((*list)[j]);
+            xfree(*list);
+            rb_jump_tag(exception);
+        }
+        xfree((*list)[i]);
+    }
+    xfree(*list);
+
+    return result;
+}
diff --git a/ext/libvirt/common.h b/ext/libvirt/common.h
new file mode 100644
index 0000000..d68e3c1
--- /dev/null
+++ b/ext/libvirt/common.h
@@ -0,0 +1,211 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+/* Macros to ease some of the boilerplate */
+VALUE generic_new(VALUE klass, void *ptr, VALUE conn,
+                  RUBY_DATA_FUNC free_func);
+
+#define generic_get(kind, v)                                            \
+    do {                                                                \
+        vir##kind##Ptr ptr;                                             \
+        Data_Get_Struct(v, vir##kind, ptr);                             \
+        if (!ptr)                                                       \
+            rb_raise(rb_eArgError, #kind " has been freed");            \
+        return ptr;                                                     \
+    } while (0);
+
+#define generic_free(kind, p)                                           \
+    do {                                                                \
+        int r;                                                          \
+        r = vir##kind##Free((vir##kind##Ptr) p);                        \
+        if (r < 0)                                                      \
+            rb_raise(rb_eSystemCallError, # kind " free failed");       \
+    } while(0);
+
+VALUE create_error(VALUE error, const char* method, virConnectPtr conn);
+
+/*
+ * Code generating macros.
+ *
+ * We only generate function bodies, not the whole function
+ * declaration.
+ */
+
+/* Generate a call to a function FUNC which returns a string. The Ruby
+ * function will return the string on success and throw an exception on
+ * error. The string returned by FUNC is freed if dealloc is true.
+ */
+#define gen_call_string(func, conn, dealloc, args...)                   \
+    do {                                                                \
+        const char *str;                                                \
+        VALUE result;                                                   \
+                                                                        \
+        str = func(args);                                               \
+        _E(str == NULL, create_error(e_Error, # func, conn));           \
+                                                                        \
+        result = rb_str_new2(str);                                      \
+        if (dealloc)                                                    \
+            xfree((void *) str);                                        \
+        return result;                                                  \
+    } while(0)
+
+/* Generate a call to vir##KIND##Free and return Qnil. Set the the embedded
+ * vir##KIND##Ptr to NULL. If that pointer is already NULL, do nothing.
+ */
+#define gen_call_free(kind, s)                                          \
+    do {                                                                \
+        vir##kind##Ptr ptr;                                             \
+        Data_Get_Struct(s, vir##kind, ptr);                             \
+        if (ptr != NULL) {                                              \
+            int r = vir##kind##Free(ptr);                               \
+            _E(r < 0, create_error(e_Error, "vir" #kind "Free", conn(s))); \
+            DATA_PTR(s) = NULL;                                         \
+        }                                                               \
+        return Qnil;                                                    \
+    } while (0)
+
+/* Generate a call to a function FUNC which returns an int error, where -1
+ * indicates error and 0 success. The Ruby function will return Qnil on
+ * success and throw an exception on error.
+ */
+#define gen_call_void(func, conn, args...)                              \
+    do {                                                                \
+        int _r_##func;                                                  \
+        _r_##func = func(args);                                         \
+        _E(_r_##func < 0, create_error(e_Error, #func, conn));          \
+        return Qnil;                                                    \
+    } while(0)
+
+/*
+ * Generate a call to a virConnectNumOf... function. C is the Ruby VALUE
+ * holding the connection and OBJS is a token indicating what objects to
+ * get the number of, e.g. 'Domains'
+ */
+#define gen_conn_num_of(c, objs)                                        \
+    do {                                                                \
+        int result;                                                     \
+        virConnectPtr conn = connect_get(c);                            \
+                                                                        \
+        result = virConnectNumOf##objs(conn);                           \
+        _E(result < 0, create_error(e_RetrieveError, "virConnectNumOf" # objs, conn));                \
+                                                                        \
+        return INT2NUM(result);                                         \
+    } while(0)
+
+
+VALUE gen_list(int num, char ***list);
+
+/*
+ * Generate a call to a virConnectList... function. S is the Ruby VALUE
+ * holding the connection and OBJS is a token indicating what objects to
+ * get the number of, e.g. 'Domains' The list function must return an array
+ * of strings, which is returned as a Ruby array
+ */
+#define gen_conn_list_names(s, objs)                                    \
+    do {                                                                \
+        int r, num;                                                     \
+        char **names;                                                   \
+        virConnectPtr conn = connect_get(s);                            \
+                                                                        \
+        num = virConnectNumOf##objs(conn);                              \
+        _E(num < 0, create_error(e_RetrieveError, "virConnectNumOf" # objs, conn));   \
+        if (num == 0) {                                                 \
+            /* if num is 0, don't call virConnectList* function */      \
+            return rb_ary_new2(num);                                    \
+        }                                                               \
+        names = ALLOC_N(char *, num);                                   \
+        r = virConnectList##objs(conn, names, num);                     \
+        if (r < 0) {                                                    \
+            xfree(names);                                               \
+            _E(r < 0, create_error(e_RetrieveError, "virConnectList" # objs, conn));  \
+        }                                                               \
+                                                                        \
+        return gen_list(num, &names);                                   \
+    } while(0)
+
+/* Generate a call to a function FUNC which returns an int; -1 indicates
+ * error, 0 indicates Qfalse, and 1 indicates Qtrue.
+ */
+#define gen_call_truefalse(func, conn, args...)                         \
+    do {                                                                \
+        int _r_##func;                                                  \
+        _r_##func = func(args);                                         \
+        _E(_r_##func < 0, create_error(e_Error, #func, conn));          \
+        return _r_##func ? Qtrue : Qfalse;                              \
+    } while(0)
+
+/* Generate a call to a function FUNC which returns an int error, where -1
+ * indicates error and >= 0 success. The Ruby function will return the integer
+ * success and throw an exception on error.
+ */
+#define gen_call_int(func, conn, args...)                               \
+    do {                                                                \
+        int _r_##func;                                                  \
+        _r_##func = func(args);                                         \
+        _E(_r_##func < 0, create_error(e_RetrieveError, #func, conn));  \
+        return INT2NUM(_r_##func);                                      \
+    } while(0)
+
+/* Error handling */
+#define _E(cond, excep) \
+    do { if (cond) rb_exc_raise(excep); } while(0)
+
+int is_symbol_or_proc(VALUE handle);
+
+extern VALUE e_RetrieveError;
+extern VALUE e_Error;
+extern VALUE e_DefinitionError;
+extern VALUE e_NoSupportError;
+
+extern VALUE m_libvirt;
+
+char *get_string_or_nil(VALUE arg);
+
+struct rb_ary_entry_arg {
+    VALUE arr;
+    int elem;
+};
+VALUE rb_ary_entry_wrap(VALUE arg);
+VALUE rb_ary_new_wrap(VALUE arg);
+struct rb_ary_push_arg {
+    VALUE arr;
+    VALUE value;
+};
+VALUE rb_ary_push_wrap(VALUE arg);
+VALUE rb_ary_new2_wrap(VALUE arg);
+
+VALUE rb_str_new2_wrap(VALUE arg);
+struct rb_str_new_arg {
+    char *val;
+    size_t size;
+};
+VALUE rb_str_new_wrap(VALUE arg);
+VALUE rb_string_value_cstr_wrap(VALUE arg);
+
+struct rb_iv_set_arg {
+    VALUE klass;
+    char *member;
+    VALUE value;
+};
+VALUE rb_iv_set_wrap(VALUE arg);
+
+struct rb_class_new_instance_arg {
+    int argc;
+    VALUE *argv;
+    VALUE klass;
+};
+VALUE rb_class_new_instance_wrap(VALUE arg);
+
+#ifndef RARRAY_LEN
+#define RARRAY_LEN(ar) (RARRAY(ar)->len)
+#endif
+
+#ifndef RSTRING_PTR
+#define RSTRING_PTR(str) (RSTRING(str)->ptr)
+#endif
+
+#ifndef RSTRING_LEN
+#define RSTRING_LEN(str) (RSTRING(str)->len)
+#endif
+
+#endif
diff --git a/ext/libvirt/connect.c b/ext/libvirt/connect.c
new file mode 100644
index 0000000..8f511d6
--- /dev/null
+++ b/ext/libvirt/connect.c
@@ -0,0 +1,2265 @@
+/*
+ * connect.c: virConnect methods
+ *
+ * Copyright (C) 2007,2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "extconf.h"
+#include "common.h"
+#include "domain.h"
+#include "network.h"
+
+static VALUE c_connect;
+static VALUE c_node_security_model;
+static VALUE c_node_info;
+
+static void connect_close(void *p) {
+    int r;
+
+    if (!p)
+        return;
+    r = virConnectClose((virConnectPtr) p);
+    _E(r < 0, create_error(rb_eSystemCallError, "virConnectClose", p));
+}
+
+VALUE connect_new(virConnectPtr p) {
+    return Data_Wrap_Struct(c_connect, NULL, connect_close, p);
+}
+
+virConnectPtr connect_get(VALUE s) {
+    generic_get(Connect, s);
+}
+
+VALUE conn_attr(VALUE s) {
+    if (rb_obj_is_instance_of(s, c_connect) != Qtrue) {
+        s = rb_iv_get(s, "@connection");
+    }
+    if (rb_obj_is_instance_of(s, c_connect) != Qtrue) {
+        rb_raise(rb_eArgError, "Expected Connection object");
+    }
+    return s;
+}
+
+virConnectPtr conn(VALUE s) {
+    virConnectPtr conn;
+
+    s = conn_attr(s);
+    Data_Get_Struct(s, virConnect, conn);
+    if (!conn)
+        rb_raise(rb_eArgError, "Connection has been closed");
+    return conn;
+}
+
+/*
+ * call-seq:
+ *   conn.close -> nil
+ *
+ * Call +virConnectClose+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectClose]
+ * to close the connection.
+ */
+static VALUE libvirt_conn_close(VALUE s) {
+    virConnectPtr conn;
+    Data_Get_Struct(s, virConnect, conn);
+    if (conn) {
+        connect_close(conn);
+        DATA_PTR(s) = NULL;
+    }
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *   conn.closed? -> [True|False]
+ *
+ * Return +true+ if the connection is closed, +false+ if it is open.
+ */
+static VALUE libvirt_conn_closed_p(VALUE s) {
+    virConnectPtr conn;
+
+    Data_Get_Struct(s, virConnect, conn);
+    return (conn==NULL) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   conn.type -> string
+ *
+ * Call +virConnectGetType+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetType]
+ * to retrieve the type of hypervisor for this connection.
+ */
+static VALUE libvirt_conn_type(VALUE s) {
+    gen_call_string(virConnectGetType, conn(s), 0, connect_get(s));
+}
+
+/*
+ * call-seq:
+ *   conn.version -> fixnum
+ *
+ * Call +virConnectGetVersion+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetVersion]
+ * to retrieve the version of the hypervisor for this connection.
+ */
+static VALUE libvirt_conn_version(VALUE s) {
+    int r;
+    unsigned long v;
+    virConnectPtr conn = connect_get(s);
+
+    r = virConnectGetVersion(conn, &v);
+    _E(r < 0, create_error(e_RetrieveError, "virConnectGetVersion", conn));
+
+    return ULONG2NUM(v);
+}
+
+#if HAVE_VIRCONNECTGETLIBVERSION
+/*
+ * call-seq:
+ *   conn.libversion -> fixnum
+ *
+ * Call +virConnectGetLibVersion+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetLibVersion]
+ * to retrieve the version of the libvirt library for this connection.
+ */
+static VALUE libvirt_conn_libversion(VALUE s) {
+    int r;
+    unsigned long v;
+    virConnectPtr conn = connect_get(s);
+
+    r = virConnectGetLibVersion(conn, &v);
+    _E(r < 0, create_error(e_RetrieveError, "virConnectGetLibVersion", conn));
+
+    return ULONG2NUM(v);
+}
+#endif
+
+/*
+ * call-seq:
+ *   conn.hostname -> string
+ *
+ * Call +virConnectGetHostname+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetHostname]
+ * to retrieve the hostname of the hypervisor for this connection.
+ */
+static VALUE libvirt_conn_hostname(VALUE s) {
+    gen_call_string(virConnectGetHostname, conn(s), 1, connect_get(s));
+}
+
+/*
+ * call-seq:
+ *   conn.uri -> string
+ *
+ * Call +virConnectGetURI+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetURI]
+ * to retrieve the canonical URI for this connection.
+ */
+static VALUE libvirt_conn_uri(VALUE s) {
+    gen_call_string(virConnectGetURI, conn(s), 1, connect_get(s));
+}
+
+/*
+ * call-seq:
+ *   conn.max_vcpus(type=nil) -> fixnum
+ *
+ * Call +virConnectGetMaxVcpus+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetMaxVcpus]
+ * to retrieve the maximum number of virtual cpus supported by the hypervisor
+ * for this connection.
+ */
+static VALUE libvirt_conn_max_vcpus(int argc, VALUE *argv, VALUE s) {
+    VALUE type;
+
+    rb_scan_args(argc, argv, "01", &type);
+
+    gen_call_int(virConnectGetMaxVcpus, conn(s), connect_get(s),
+                 get_string_or_nil(type));
+}
+
+/*
+ * call-seq:
+ *   conn.node_get_info -> Libvirt::Connect::Nodeinfo
+ *
+ * Call +virNodeGetInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeGetInfo]
+ * to retrieve information about the node for this connection.
+ */
+static VALUE libvirt_conn_node_get_info(VALUE s) {
+    int r;
+    virConnectPtr conn = connect_get(s);
+    virNodeInfo nodeinfo;
+    VALUE result;
+
+    r = virNodeGetInfo(conn, &nodeinfo);
+    _E(r < 0, create_error(e_RetrieveError, "virNodeGetInfo", conn));
+
+    result = rb_class_new_instance(0, NULL, c_node_info);
+    rb_iv_set(result, "@model", rb_str_new2(nodeinfo.model));
+    rb_iv_set(result, "@memory", ULONG2NUM(nodeinfo.memory));
+    rb_iv_set(result, "@cpus", UINT2NUM(nodeinfo.cpus));
+    rb_iv_set(result, "@mhz", UINT2NUM(nodeinfo.mhz));
+    rb_iv_set(result, "@nodes", UINT2NUM(nodeinfo.nodes));
+    rb_iv_set(result, "@sockets", UINT2NUM(nodeinfo.sockets));
+    rb_iv_set(result, "@cores", UINT2NUM(nodeinfo.cores));
+    rb_iv_set(result, "@threads", UINT2NUM(nodeinfo.threads));
+
+    return result;
+}
+
+/*
+ * call-seq:
+ *   conn.node_free_memory -> fixnum
+ *
+ * Call +virNodeGetFreeMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeGetFreeMemory]
+ * to retrieve the amount of free memory available on the host for this
+ * connection.
+ */
+static VALUE libvirt_conn_node_free_memory(VALUE s) {
+    virConnectPtr conn = connect_get(s);
+    unsigned long long freemem;
+
+    freemem = virNodeGetFreeMemory(conn);
+
+    _E(freemem == 0, create_error(e_RetrieveError, "virNodeGetFreeMemory",
+                                  conn));
+
+    return ULL2NUM(freemem);
+}
+
+/*
+ * call-seq:
+ *   conn.node_cells_free_memory(startCell=0, maxCells=#nodeCells) -> list
+ *
+ * Call +virNodeGetCellsFreeMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeGetCellsFreeMemory]
+ * to retrieve the amount of free memory in each NUMA cell on the host for
+ * this connection.
+ */
+static VALUE libvirt_conn_node_cells_free_memory(int argc, VALUE *argv,
+                                                 VALUE s) {
+    int r;
+    virConnectPtr conn = connect_get(s);
+    VALUE cells;
+    VALUE start, max;
+    unsigned long long *freeMems;
+    virNodeInfo nodeinfo;
+    int i;
+    unsigned int startCell, maxCells;
+
+    rb_scan_args(argc, argv, "02", &start, &max);
+
+    if (NIL_P(start))
+        startCell = 0;
+    else
+        startCell = NUM2UINT(start);
+
+    if (NIL_P(max)) {
+        r = virNodeGetInfo(conn, &nodeinfo);
+        _E(r < 0, create_error(e_RetrieveError, "virNodeGetInfo", conn));
+        maxCells = nodeinfo.nodes;
+    }
+    else
+        maxCells = NUM2UINT(max);
+
+    freeMems = ALLOC_N(unsigned long long, maxCells);
+
+    r = virNodeGetCellsFreeMemory(conn, freeMems, startCell, maxCells);
+    if (r < 0) {
+        xfree(freeMems);
+        rb_exc_raise(create_error(e_RetrieveError, "virNodeGetCellsFreeMemory",
+                                  conn));
+    }
+
+    cells = rb_ary_new2(r);
+    for (i = 0; i < r; i++)
+        rb_ary_push(cells, ULL2NUM(freeMems[i]));
+    xfree(freeMems);
+
+    return cells;
+}
+
+#if HAVE_VIRNODEGETSECURITYMODEL
+/*
+ * call-seq:
+ *   conn.node_get_security_model -> Libvirt::Connect::NodeSecurityModel
+ *
+ * Call +virNodeGetSecurityModel+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeGetSecurityModel]
+ * to retrieve the security model in use on the host for this connection.
+ */
+static VALUE libvirt_conn_node_get_security_model(VALUE s) {
+    virSecurityModel secmodel;
+    virConnectPtr conn = connect_get(s);
+    int r;
+    VALUE result;
+
+    r = virNodeGetSecurityModel(conn, &secmodel);
+    _E(r < 0, create_error(e_RetrieveError, "virNodeGetSecurityModel", conn));
+
+    result = rb_class_new_instance(0, NULL, c_node_security_model);
+    rb_iv_set(result, "@model", rb_str_new2(secmodel.model));
+    rb_iv_set(result, "@doi", rb_str_new2(secmodel.doi));
+
+    return result;
+}
+#endif
+
+#if HAVE_VIRCONNECTISENCRYPTED
+/*
+ * call-seq:
+ *   conn.encrypted? -> [True|False]
+ *
+ * Call +virConnectIsEncrypted+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectIsEncrypted]
+ * to determine if the connection is encrypted.
+ */
+static VALUE libvirt_conn_encrypted_p(VALUE s) {
+    gen_call_truefalse(virConnectIsEncrypted, conn(s), connect_get(s));
+}
+#endif
+
+#if HAVE_VIRCONNECTISSECURE
+/*
+ * call-seq:
+ *   conn.secure? -> [True|False]
+ *
+ * Call +virConnectIsSecure+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectIsSecure]
+ * to determine if the connection is secure.
+ */
+static VALUE libvirt_conn_secure_p(VALUE s) {
+    gen_call_truefalse(virConnectIsSecure, conn(s), connect_get(s));
+}
+#endif
+
+/*
+ * call-seq:
+ *   conn.capabilities -> string
+ *
+ * Call +virConnectGetCapabilities+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetCapabilities]
+ * to retrieve the capabilities XML for this connection.
+ */
+static VALUE libvirt_conn_capabilities(VALUE s) {
+    gen_call_string(virConnectGetCapabilities, conn(s), 1, connect_get(s));
+}
+
+#if HAVE_VIRCONNECTCOMPARECPU
+/*
+ * call-seq:
+ *   conn.compare_cpu(xml, flags=0) -> compareflag
+ *
+ * Call +virConnectCompareCPU+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectCompareCPU]
+ * to compare the host CPU with the XML contained in xml.  Returns one of
+ * Libvirt::CPU_COMPARE_ERROR, Libvirt::CPU_COMPARE_INCOMPATIBLE,
+ * Libvirt::CPU_COMPARE_IDENTICAL, or Libvirt::CPU_COMPARE_SUPERSET.
+ */
+static VALUE libvirt_conn_compare_cpu(int argc, VALUE *argv, VALUE s) {
+    VALUE xml, flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_int(virConnectCompareCPU, conn(s), connect_get(s),
+                 StringValueCStr(xml), NUM2UINT(flags));
+}
+#endif
+
+
+#if HAVE_VIRCONNECTBASELINECPU
+/*
+ * call-seq:
+ *   conn.baseline_cpu([xml, xml2, ...], flags=0) -> XML
+ *
+ * Call +virConnectBaselineCPU+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectBaselineCPU]
+ * to compare the most feature-rich CPU which is compatible with all
+ * given host CPUs.
+ */
+static VALUE libvirt_conn_baseline_cpu(int argc, VALUE *argv, VALUE s) {
+    VALUE xmlcpus, flags_val;
+    virConnectPtr conn = connect_get(s);
+    char *r;
+    VALUE retval;
+    unsigned int ncpus, flags;
+    VALUE entry;
+    const char **xmllist;
+    int i;
+    int exception = 0;
+    struct rb_ary_entry_arg arg;
+
+    rb_scan_args(argc, argv, "11", &xmlcpus, &flags_val);
+    /*
+     * We check flags up-front here so that we get a TypeError early on if
+     * flags is bogus.
+     */
+    if (NIL_P(flags_val))
+        flags = 0;
+    else
+        flags = NUM2UINT(flags_val);
+
+    Check_Type(xmlcpus, T_ARRAY);
+
+    if (RARRAY_LEN(xmlcpus) < 1)
+        rb_raise(rb_eArgError, "wrong number of cpu arguments (%d for 1 or more)",
+                 RARRAY_LEN(xmlcpus));
+
+    ncpus = RARRAY_LEN(xmlcpus);
+    xmllist = ALLOC_N(const char *, ncpus);
+
+    for (i = 0; i < ncpus; i++) {
+        arg.arr = xmlcpus;
+        arg.elem = i;
+        entry = rb_protect(rb_ary_entry_wrap, (VALUE)&arg, &exception);
+        if (exception) {
+            xfree(xmllist);
+            rb_jump_tag(exception);
+        }
+
+        xmllist[i] = (char *)rb_protect(rb_string_value_cstr_wrap,
+                                        (VALUE)&entry, &exception);
+        if (exception) {
+            xfree(xmllist);
+            rb_jump_tag(exception);
+        }
+    }
+
+    r = virConnectBaselineCPU(conn, xmllist, ncpus, flags);
+    xfree(xmllist);
+    _E(r == NULL, create_error(e_RetrieveError, "virConnectBaselineCPU", conn));
+
+    retval = rb_protect(rb_str_new2_wrap, (VALUE)&r, &exception);
+    if (exception) {
+        free(r);
+        rb_jump_tag(exception);
+    }
+
+    free(r);
+
+    return retval;
+}
+#endif
+
+#if HAVE_VIRCONNECTDOMAINEVENTREGISTERANY || HAVE_VIRCONNECTDOMAINEVENTREGISTER
+static int domain_event_lifecycle_callback(virConnectPtr conn,
+                                           virDomainPtr dom, int event,
+                                           int detail, void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE newc;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event lifecycle callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+
+    newc = connect_new(conn);
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 5, newc,
+                   domain_new(dom, newc), INT2NUM(event), INT2NUM(detail),
+                   cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 5, newc, domain_new(dom, newc),
+                   INT2NUM(event), INT2NUM(detail), cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong domain event lifecycle callback (expected Symbol or Proc)");
+
+    return 0;
+}
+#endif
+
+#if HAVE_VIRCONNECTDOMAINEVENTREGISTERANY
+static int domain_event_reboot_callback(virConnectPtr conn, virDomainPtr dom,
+                                        void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE newc;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event reboot callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+
+    newc = connect_new(conn);
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 3, newc,
+                   domain_new(dom, newc), cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 3, newc, domain_new(dom, newc),
+                   cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong domain event reboot callback (expected Symbol or Proc)");
+
+    return 0;
+}
+
+static int domain_event_rtc_callback(virConnectPtr conn, virDomainPtr dom,
+                                     long long utc_offset, void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE newc;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event rtc callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+
+    newc = connect_new(conn);
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 4, newc,
+                   domain_new(dom, newc), LL2NUM(utc_offset), cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 4, newc, domain_new(dom, newc),
+                   LL2NUM(utc_offset), cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong domain event rtc callback (expected Symbol or Proc)");
+
+    return 0;
+}
+
+static int domain_event_watchdog_callback(virConnectPtr conn, virDomainPtr dom,
+                                          int action, void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE newc;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event watchdog callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+
+    newc = connect_new(conn);
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 4, newc,
+                   domain_new(dom, newc), INT2NUM(action), cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 4, newc, domain_new(dom, newc),
+                   INT2NUM(action), cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong domain event watchdog callback (expected Symbol or Proc)");
+
+    return 0;
+}
+
+static int domain_event_io_error_callback(virConnectPtr conn, virDomainPtr dom,
+                                          const char *src_path,
+                                          const char *dev_alias,
+                                          int action,
+                                          void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE newc;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event IO error callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+
+    newc = connect_new(conn);
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 6, newc,
+                   domain_new(dom, newc), rb_str_new2(src_path),
+                   rb_str_new2(dev_alias), INT2NUM(action), cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 6, newc, domain_new(dom, newc),
+                   rb_str_new2(src_path), rb_str_new2(dev_alias),
+                   INT2NUM(action), cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong domain event IO error callback (expected Symbol or Proc)");
+
+    return 0;
+}
+
+static int domain_event_io_error_reason_callback(virConnectPtr conn,
+                                                 virDomainPtr dom,
+                                                 const char *src_path,
+                                                 const char *dev_alias,
+                                                 int action,
+                                                 const char *reason,
+                                                 void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE newc;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event IO error reason callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+
+    newc = connect_new(conn);
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 7, newc,
+                   domain_new(dom, newc), rb_str_new2(src_path),
+                   rb_str_new2(dev_alias), INT2NUM(action),
+                   rb_str_new2(reason), cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 7, newc, domain_new(dom, newc),
+                   rb_str_new2(src_path), rb_str_new2(dev_alias),
+                   INT2NUM(action), rb_str_new2(reason), cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong domain event IO error reason callback (expected Symbol or Proc)");
+
+    return 0;
+}
+
+static int domain_event_graphics_callback(virConnectPtr conn, virDomainPtr dom,
+                                          int phase,
+                                          virDomainEventGraphicsAddressPtr local,
+                                          virDomainEventGraphicsAddressPtr remote,
+                                          const char *authScheme,
+                                          virDomainEventGraphicsSubjectPtr subject,
+                                          void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE newc;
+    VALUE local_hash;
+    VALUE remote_hash;
+    VALUE subject_array;
+    VALUE pair;
+    int i;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event graphics callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+
+    local_hash = rb_hash_new();
+    rb_hash_aset(local_hash, rb_str_new2("family"), INT2NUM(local->family));
+    rb_hash_aset(local_hash, rb_str_new2("node"), rb_str_new2(local->node));
+    rb_hash_aset(local_hash, rb_str_new2("service"),
+                 rb_str_new2(local->service));
+
+    remote_hash = rb_hash_new();
+    rb_hash_aset(remote_hash, rb_str_new2("family"), INT2NUM(remote->family));
+    rb_hash_aset(remote_hash, rb_str_new2("node"), rb_str_new2(remote->node));
+    rb_hash_aset(remote_hash, rb_str_new2("service"),
+                 rb_str_new2(remote->service));
+
+    subject_array = rb_ary_new();
+    for (i = 0; i < subject->nidentity; i++) {
+        pair = rb_ary_new();
+        rb_ary_store(pair, 0, rb_str_new2(subject->identities[i].type));
+        rb_ary_store(pair, 1, rb_str_new2(subject->identities[i].name));
+
+        rb_ary_store(subject_array, i, pair);
+    }
+
+    newc = connect_new(conn);
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 8, newc,
+                   domain_new(dom, newc), INT2NUM(phase), local_hash,
+                   remote_hash, rb_str_new2(authScheme), subject_array,
+                   cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 8, newc, domain_new(dom, newc),
+                   INT2NUM(phase), local_hash, remote_hash,
+                   rb_str_new2(authScheme), subject_array, cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong domain event graphics callback (expected Symbol or Proc)");
+
+    return 0;
+}
+
+/*
+ * call-seq:
+ *   conn.domain_event_register_any(eventID, callback, dom=nil, opaque=nil) -> fixnum
+ *
+ * Call +virConnectDomainEventRegisterAny+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventRegisterAny]
+ * to register callback for eventID with libvirt.  The eventID must be one of
+ * the Libvirt::Connect::DOMAIN_EVENT_ID_* constants.  The callback can either
+ * be a Symbol (that is the name of a method to callback) or a Proc.  Note that
+ * the callback must accept different numbers of arguments depending on the
+ * eventID passed in.  The arguments are as follows:
+ *
+ * - DOMAIN_EVENT_ID_LIFECYCLE: Libvirt::Connect, Libvirt::Domain, event, detail, opaque
+ * - DOMAIN_EVENT_ID_REBOOT: Libvirt::Connect, Libvirt::Domain, opaque
+ * - DOMAIN_EVENT_ID_RTC_CHANGE: Libvirt::Connect, Libvirt::Domain, utc_offset, opaque
+ * - DOMAIN_EVENT_ID_WATCHDOG: Libvirt::Connect, Libvirt::Domain, action, opaque
+ * - DOMAIN_EVENT_ID_IO_ERROR: Libvirt::Connect, Libvirt::Domain, src_path, dev_alias, action, opaque
+ * - DOMAIN_EVENT_ID_IO_ERROR_REASON: Libvirt::Connect, Libvirt::Domain, src_path, dev_alias, action, reason, opaque
+ * - DOMAIN_EVENT_ID_GRAPHICS: Libvirt::Connect, Libvirt::Domain, phase, local, remote, auth_scheme, subject, opaque
+
+ * If dom is a valid Libvirt::Domain object, then only events from that
+ * domain will be seen.  The opaque parameter can be any valid ruby type, and
+ * will be passed into callback as "opaque".  This method returns a
+ * libvirt-specific handle, which must be used by the application to
+ * deregister the callback later (see domain_event_deregister_any).
+ */
+static VALUE libvirt_conn_domain_event_register_any(int argc, VALUE *argv,
+                                                    VALUE c) {
+    VALUE eventID, cb, dom, opaque;
+    virDomainPtr domain;
+    virConnectDomainEventGenericCallback internalcb = NULL;
+    VALUE passthrough;
+
+    rb_scan_args(argc, argv, "22", &eventID, &cb, &dom, &opaque);
+
+    if (!is_symbol_or_proc(cb))
+        rb_raise(rb_eTypeError, "wrong argument type (expected Symbol or Proc)");
+
+    if (NIL_P(dom))
+        domain = NULL;
+    else
+        domain = domain_get(dom);
+
+    switch(NUM2INT(eventID)) {
+    case VIR_DOMAIN_EVENT_ID_LIFECYCLE:
+        internalcb = VIR_DOMAIN_EVENT_CALLBACK(domain_event_lifecycle_callback);
+        break;
+    case VIR_DOMAIN_EVENT_ID_REBOOT:
+        internalcb = VIR_DOMAIN_EVENT_CALLBACK(domain_event_reboot_callback);
+        break;
+    case VIR_DOMAIN_EVENT_ID_RTC_CHANGE:
+        internalcb = VIR_DOMAIN_EVENT_CALLBACK(domain_event_rtc_callback);
+        break;
+    case VIR_DOMAIN_EVENT_ID_WATCHDOG:
+        internalcb = VIR_DOMAIN_EVENT_CALLBACK(domain_event_watchdog_callback);
+        break;
+    case VIR_DOMAIN_EVENT_ID_IO_ERROR:
+        internalcb = VIR_DOMAIN_EVENT_CALLBACK(domain_event_io_error_callback);
+        break;
+    case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON:
+        internalcb = VIR_DOMAIN_EVENT_CALLBACK(domain_event_io_error_reason_callback);
+        break;
+    case VIR_DOMAIN_EVENT_ID_GRAPHICS:
+        internalcb = VIR_DOMAIN_EVENT_CALLBACK(domain_event_graphics_callback);
+        break;
+    default:
+        rb_raise(rb_eArgError, "invalid eventID argument %d",
+                 NUM2INT(eventID));
+        break;
+    }
+
+    passthrough = rb_ary_new();
+    rb_ary_store(passthrough, 0, cb);
+    rb_ary_store(passthrough, 1, opaque);
+
+    gen_call_int(virConnectDomainEventRegisterAny, conn(c), connect_get(c),
+                 domain, NUM2INT(eventID), internalcb, (void *)passthrough,
+                 NULL);
+}
+
+/*
+ * call-seq:
+ *   conn.domain_event_deregister_any(callbackID) -> nil
+ *
+ * Call +virConnectDomainEventDeregisterAny+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventDeregisterAny]
+ * to deregister a callback from libvirt.  The callbackID must be a
+ * libvirt-specific handle returned by domain_event_register_any.
+ */
+static VALUE libvirt_conn_domain_event_deregister_any(VALUE c,
+                                                      VALUE callbackID) {
+    gen_call_void(virConnectDomainEventDeregisterAny, conn(c), connect_get(c),
+                  NUM2INT(callbackID));
+}
+#endif
+
+#if HAVE_VIRCONNECTDOMAINEVENTREGISTER
+/*
+ * this is a bit of silliness.  Because libvirt internals track the address
+ * of the function pointer, trying to use domain_event_lifecycle_callback
+ * for both register and register_any would mean that we could only register
+ * one or the other for lifecycle callbacks.  Instead we do a simple wrapper
+ * so that the addresses are different
+ */
+static int domain_event_callback(virConnectPtr conn,
+                                 virDomainPtr dom, int event,
+                                 int detail, void *opaque) {
+    return domain_event_lifecycle_callback(conn, dom, event, detail, opaque);
+}
+/*
+ * call-seq:
+ *   conn.domain_event_register(callback, opaque=nil) -> nil
+ *
+ * Call +virConnectDomainEventRegister+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventRegister]
+ * to register callback for domain lifecycle events with libvirt.  The
+ * callback can either be a Symbol (that is the name of a method to callback)
+ * or a Proc.  The callback must accept 5 parameters: Libvirt::Connect,
+ * Libvirt::Domain, event, detail, opaque.  The opaque parameter to
+ * domain_event_register can be any valid ruby type, and will be passed into
+ * callback as "opaque".  This method is deprecated in favor of
+ * domain_event_register_any.
+ */
+static VALUE libvirt_conn_domain_event_register(int argc, VALUE *argv,
+                                                VALUE c) {
+    VALUE cb, opaque;
+    VALUE passthrough;
+
+    rb_scan_args(argc, argv, "11", &cb, &opaque);
+
+    if (!is_symbol_or_proc(cb))
+        rb_raise(rb_eTypeError, "wrong argument type (expected Symbol or Proc)");
+
+    passthrough = rb_ary_new();
+    rb_ary_store(passthrough, 0, cb);
+    rb_ary_store(passthrough, 1, opaque);
+
+    gen_call_void(virConnectDomainEventRegister, conn(c), connect_get(c),
+                  domain_event_callback, (void *)passthrough, NULL);
+}
+
+/*
+ * call-seq:
+ *   conn.domain_event_deregister(callback) -> nil
+ *
+ * Call +virConnectDomainEventDeregister+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventDeregister]
+ * to deregister the event callback from libvirt.  This method is deprecated
+ * in favor of domain_event_deregister_any (though they cannot be mixed; if
+ * the callback was registered with domain_event_register, it must be
+ * deregistered with domain_event_deregister).
+ */
+static VALUE libvirt_conn_domain_event_deregister(VALUE c) {
+    gen_call_void(virConnectDomainEventDeregister, conn(c), connect_get(c),
+                  domain_event_callback);
+}
+#endif
+
+/*
+ * call-seq:
+ *   conn.num_of_domains -> fixnum
+ *
+ * Call +virConnectNumOfDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDomains]
+ * to retrieve the number of active domains on this connection.
+ */
+static VALUE libvirt_conn_num_of_domains(VALUE s) {
+    gen_conn_num_of(s, Domains);
+}
+
+/*
+ * call-seq:
+ *   conn.list_domains -> list
+ *
+ * Call +virConnectListDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDomains]
+ * to retrieve a list of active domain IDs on this connection.
+ */
+static VALUE libvirt_conn_list_domains(VALUE s) {
+    int i, r, num, *ids;
+    virConnectPtr conn = connect_get(s);
+    VALUE result;
+    int exception = 0;
+    struct rb_ary_push_arg args;
+
+    num = virConnectNumOfDomains(conn);
+    _E(num < 0, create_error(e_RetrieveError, "virConnectNumOfDomains", conn));
+    if (num == 0) {
+        result = rb_ary_new2(num);
+        return result;
+    }
+
+    ids = ALLOC_N(int, num);
+    r = virConnectListDomains(conn, ids, num);
+    if (r < 0) {
+        xfree(ids);
+        rb_exc_raise(create_error(e_RetrieveError, "virConnectListDomains",
+                                  conn));
+    }
+
+    result = rb_protect(rb_ary_new2_wrap, (VALUE)&num, &exception);
+    if (exception) {
+        xfree(ids);
+        rb_jump_tag(exception);
+    }
+
+    for (i = 0; i < num; i++) {
+        args.arr = result;
+        args. value = INT2NUM(ids[i]);
+        rb_protect(rb_ary_push_wrap, (VALUE)&args, &exception);
+        if (exception) {
+            xfree(ids);
+            rb_jump_tag(exception);
+        }
+    }
+    xfree(ids);
+    return result;
+}
+
+/*
+ * call-seq:
+ *   conn.num_of_defined_domains -> fixnum
+ *
+ * Call +virConnectNumOfDefinedDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDefinedDomains]
+ * to retrieve the number of inactive domains on this connection.
+ */
+static VALUE libvirt_conn_num_of_defined_domains(VALUE s) {
+    gen_conn_num_of(s, DefinedDomains);
+}
+
+/*
+ * call-seq:
+ *   conn.list_defined_domains -> list
+ *
+ * Call +virConnectListDefinedDomains+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDefinedDomains]
+ * to retrieve a list of inactive domain names on this connection.
+ */
+static VALUE libvirt_conn_list_defined_domains(VALUE s) {
+    gen_conn_list_names(s, DefinedDomains);
+}
+
+/*
+ * call-seq:
+ *   conn.create_domain_linux(xml, flags=0) -> Libvirt::Domain
+ *
+ * Call +virDomainCreateLinux+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCreateLinux]
+ * to start a transient domain from the given XML.  Deprecated; use
+ * conn.create_domain_xml instead.
+ */
+static VALUE libvirt_conn_create_linux(int argc, VALUE *argv, VALUE c) {
+    virDomainPtr dom;
+    virConnectPtr conn = connect_get(c);
+    VALUE flags, xml;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    dom = virDomainCreateLinux(conn, StringValueCStr(xml), NUM2UINT(flags));
+    _E(dom == NULL, create_error(e_Error, "virDomainCreateLinux", conn));
+
+    return domain_new(dom, c);
+}
+
+#if HAVE_VIRDOMAINCREATEXML
+/*
+ * call-seq:
+ *   conn.create_domain_xml(xml, flags=0) -> Libvirt::Domain
+ *
+ * Call +virDomainCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCreateXML]
+ * to start a transient domain from the given XML.
+ */
+static VALUE libvirt_conn_create_xml(int argc, VALUE *argv, VALUE c) {
+    virDomainPtr dom;
+    virConnectPtr conn = connect_get(c);
+    VALUE flags, xml;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    dom = virDomainCreateXML(conn, StringValueCStr(xml), NUM2UINT(flags));
+    _E(dom == NULL, create_error(e_Error, "virDomainCreateXML", conn));
+
+    return domain_new(dom, c);
+}
+#endif
+
+/*
+ * call-seq:
+ *   conn.lookup_domain_by_name(name) -> Libvirt::Domain
+ *
+ * Call +virDomainLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainLookupByName]
+ * to retrieve a domain object for name.
+ */
+static VALUE libvirt_conn_lookup_domain_by_name(VALUE c, VALUE name) {
+    virDomainPtr dom;
+    virConnectPtr conn = connect_get(c);
+
+    dom = virDomainLookupByName(conn, StringValueCStr(name));
+    _E(dom == NULL, create_error(e_RetrieveError, "virDomainLookupByName",
+                                 conn));
+
+    return domain_new(dom, c);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_domain_by_id(id) -> Libvirt::Domain
+ *
+ * Call +virDomainLookupByID+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainLookupByID]
+ * to retrieve a domain object for id.
+ */
+static VALUE libvirt_conn_lookup_domain_by_id(VALUE c, VALUE id) {
+    virDomainPtr dom;
+    virConnectPtr conn = connect_get(c);
+
+    dom = virDomainLookupByID(conn, NUM2INT(id));
+    _E(dom == NULL, create_error(e_RetrieveError, "virDomainLookupByID",
+                                 conn));
+
+    return domain_new(dom, c);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_domain_by_uuid(uuid) -> Libvirt::Domain
+ *
+ * Call +virDomainLookupByUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainLookupByUUIDString]
+ * to retrieve a domain object for uuid.
+ */
+static VALUE libvirt_conn_lookup_domain_by_uuid(VALUE c, VALUE uuid) {
+    virDomainPtr dom;
+    virConnectPtr conn = connect_get(c);
+
+    dom = virDomainLookupByUUIDString(conn, StringValueCStr(uuid));
+    _E(dom == NULL, create_error(e_RetrieveError, "virDomainLookupByUUID",
+                                 conn));
+
+    return domain_new(dom, c);
+}
+
+/*
+ * call-seq:
+ *   conn.define_domain_xml(xml) -> Libvirt::Domain
+ *
+ * Call +virDomainDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainDefineXML]
+ * to define a permanent domain on this connection.
+ */
+static VALUE libvirt_conn_define_domain_xml(VALUE c, VALUE xml) {
+    virDomainPtr dom;
+    virConnectPtr conn = connect_get(c);
+
+    dom = virDomainDefineXML(conn, StringValueCStr(xml));
+    _E(dom == NULL, create_error(e_DefinitionError, "virDomainDefineXML",
+                                 conn));
+
+    return domain_new(dom, c);
+}
+
+#if HAVE_VIRCONNECTDOMAINXMLFROMNATIVE
+/*
+ * call-seq:
+ *   conn.domain_xml_from_native(nativeFormat, xml, flags=0) -> string
+ *
+ * Call +virConnectDomainXMLFromNative+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainXMLFromNative]
+ * to convert a native hypervisor domain representation to libvirt XML.
+ */
+static VALUE libvirt_conn_domain_xml_from_native(int argc, VALUE *argv,
+                                                 VALUE s) {
+    VALUE nativeFormat, xml, flags;
+    char *ret;
+    VALUE result;
+
+    rb_scan_args(argc, argv, "21", &nativeFormat, &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    ret = virConnectDomainXMLFromNative(conn(s), StringValueCStr(nativeFormat),
+                                        StringValueCStr(xml), NUM2UINT(flags));
+    _E(ret == NULL, create_error(e_Error, "virConnectDomainXMLFromNative",
+                                 conn(s)));
+
+    result = rb_str_new2(ret);
+
+    free(ret);
+
+    return result;
+}
+#endif
+
+#if HAVE_VIRCONNECTDOMAINXMLTONATIVE
+/*
+ * call-seq:
+ *   conn.domain_xml_to_native(nativeFormat, xml, flags=0) -> string
+ *
+ * Call +virConnectDomainXMLToNative+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainXMLToNative]
+ * to convert libvirt XML to a native domain hypervisor representation.
+ */
+static VALUE libvirt_conn_domain_xml_to_native(int argc, VALUE *argv, VALUE s) {
+    VALUE nativeFormat, xml, flags;
+    char *ret;
+    VALUE result;
+
+    rb_scan_args(argc, argv, "21", &nativeFormat, &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    ret = virConnectDomainXMLToNative(conn(s), StringValueCStr(nativeFormat),
+                                      StringValueCStr(xml), NUM2UINT(flags));
+    _E(ret == NULL, create_error(e_Error, "virConnectDomainXMLToNative",
+                                 conn(s)));
+
+    result = rb_str_new2(ret);
+
+    free(ret);
+
+    return result;
+}
+#endif
+
+#if HAVE_TYPE_VIRINTERFACEPTR
+/*
+ * call-seq:
+ *   conn.num_of_interfaces -> fixnum
+ *
+ * Call +virConnectNumOfInterfaces+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfInterfaces]
+ * to retrieve the number of active interfaces on this connection.
+ */
+static VALUE libvirt_conn_num_of_interfaces(VALUE s) {
+    gen_conn_num_of(s, Interfaces);
+}
+
+/*
+ * call-seq:
+ *   conn.list_interfaces -> list
+ *
+ * Call +virConnectListInterfaces+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListInterfaces]
+ * to retrieve a list of active interface names on this connection.
+ */
+static VALUE libvirt_conn_list_interfaces(VALUE s) {
+    gen_conn_list_names(s, Interfaces);
+}
+
+/*
+ * call-seq:
+ *   conn.num_of_defined_interfaces -> fixnum
+ *
+ * Call +virConnectNumOfDefinedInterfaces+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDefinedInterfaces]
+ * to retrieve the number of inactive interfaces on this connection.
+ */
+static VALUE libvirt_conn_num_of_defined_interfaces(VALUE s) {
+    gen_conn_num_of(s, DefinedInterfaces);
+}
+
+/*
+ * call-seq:
+ *   conn.list_defined_interfaces -> list
+ *
+ * Call +virConnectListDefinedInterfaces+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDefinedInterfaces]
+ * to retrieve a list of inactive interface names on this connection.
+ */
+static VALUE libvirt_conn_list_defined_interfaces(VALUE s) {
+    gen_conn_list_names(s, DefinedInterfaces);
+}
+
+extern VALUE interface_new(virInterfacePtr i, VALUE conn);
+/*
+ * call-seq:
+ *   conn.lookup_interface_by_name(name) -> Libvirt::Interface
+ *
+ * Call +virInterfaceLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceLookupByName]
+ * to retrieve an interface object by name.
+ */
+static VALUE libvirt_conn_lookup_interface_by_name(VALUE c, VALUE name) {
+    virInterfacePtr iface;
+    virConnectPtr conn = connect_get(c);
+
+    iface = virInterfaceLookupByName(conn, StringValueCStr(name));
+    _E(iface == NULL, create_error(e_RetrieveError, "virInterfaceLookupByName",
+                                   conn));
+
+    return interface_new(iface, c);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_interface_by_mac(mac) -> Libvirt::Interface
+ *
+ * Call +virInterfaceLookupByMACString+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceLookupByMACString]
+ * to retrieve an interface object by MAC address.
+ */
+static VALUE libvirt_conn_lookup_interface_by_mac(VALUE c, VALUE mac) {
+    virInterfacePtr iface;
+    virConnectPtr conn = connect_get(c);
+
+    iface = virInterfaceLookupByMACString(conn, StringValueCStr(mac));
+    _E(iface == NULL, create_error(e_RetrieveError,
+                                   "virInterfaceLookupByMACString", conn));
+
+    return interface_new(iface, c);
+}
+
+/*
+ * call-seq:
+ *   conn.define_interface_xml(xml, flags=0) -> Libvirt::Interface
+ *
+ * Call +virInterfaceDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceDefineXML]
+ * to define a new interface from xml.
+ */
+static VALUE libvirt_conn_define_interface_xml(int argc, VALUE *argv, VALUE c) {
+    virInterfacePtr iface;
+    virConnectPtr conn = connect_get(c);
+    VALUE xml, flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    iface = virInterfaceDefineXML(conn, StringValueCStr(xml), NUM2UINT(flags));
+    _E(iface == NULL, create_error(e_DefinitionError, "virInterfaceDefineXML",
+                                   conn));
+
+    return interface_new(iface, c);
+}
+#endif
+
+/*
+ * call-seq:
+ *   conn.num_of_networks -> fixnum
+ *
+ * Call +virConnectNumOfNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfNetworks]
+ * to retrieve the number of active networks on this connection.
+ */
+static VALUE libvirt_conn_num_of_networks(VALUE s) {
+    gen_conn_num_of(s, Networks);
+}
+
+/*
+ * call-seq:
+ *   conn.list_networks -> list
+ *
+ * Call +virConnectListNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListNetworks]
+ * to retrieve a list of active network names on this connection.
+ */
+static VALUE libvirt_conn_list_networks(VALUE s) {
+    gen_conn_list_names(s, Networks);
+}
+
+/*
+ * call-seq:
+ *   conn.num_of_defined_networks -> fixnum
+ *
+ * Call +virConnectNumOfDefinedNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDefinedNetworks]
+ * to retrieve the number of inactive networks on this connection.
+ */
+static VALUE libvirt_conn_num_of_defined_networks(VALUE s) {
+    gen_conn_num_of(s, DefinedNetworks);
+}
+
+/*
+ * call-seq:
+ *   conn.list_of_defined_networks -> list
+ *
+ * Call +virConnectListDefinedNetworks+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDefinedNetworks]
+ * to retrieve a list of inactive network names on this connection.
+ */
+static VALUE libvirt_conn_list_defined_networks(VALUE s) {
+    gen_conn_list_names(s, DefinedNetworks);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_network_by_name(name) -> Libvirt::Network
+ *
+ * Call +virNetworkLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkLookupByName]
+ * to retrieve a network object by name.
+ */
+static VALUE libvirt_conn_lookup_network_by_name(VALUE c, VALUE name) {
+    virNetworkPtr netw;
+    virConnectPtr conn = connect_get(c);
+
+    netw = virNetworkLookupByName(conn, StringValueCStr(name));
+    _E(netw == NULL, create_error(e_RetrieveError, "virNetworkLookupByName",
+                                  conn));
+
+    return network_new(netw, c);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_network_by_uuid(uuid) -> Libvirt::Network
+ *
+ * Call +virNetworkLookupByUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkLookupByUUIDString]
+ * to retrieve a network object by UUID.
+ */
+static VALUE libvirt_conn_lookup_network_by_uuid(VALUE c, VALUE uuid) {
+    virNetworkPtr netw;
+    virConnectPtr conn = connect_get(c);
+
+    netw = virNetworkLookupByUUIDString(conn, StringValueCStr(uuid));
+    _E(netw == NULL, create_error(e_RetrieveError, "virNetworkLookupByUUID",
+                                  conn));
+
+    return network_new(netw, c);
+}
+
+/*
+ * call-seq:
+ *   conn.create_network_xml(xml) -> Libvirt::Network
+ *
+ * Call +virNetworkCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkCreateXML]
+ * to start a new transient network from xml.
+ */
+static VALUE libvirt_conn_create_network_xml(VALUE c, VALUE xml) {
+    virNetworkPtr netw;
+    virConnectPtr conn = connect_get(c);
+
+    netw = virNetworkCreateXML(conn, StringValueCStr(xml));
+    _E(netw == NULL, create_error(e_Error, "virNetworkCreateXML", conn));
+
+    return network_new(netw, c);
+}
+
+/*
+ * call-seq:
+ *   conn.define_network_xml(xml) -> Libvirt::Network
+ *
+ * Call +virNetworkDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkDefineXML]
+ * to define a new permanent network from xml.
+ */
+static VALUE libvirt_conn_define_network_xml(VALUE c, VALUE xml) {
+    virNetworkPtr netw;
+    virConnectPtr conn = connect_get(c);
+
+    netw = virNetworkDefineXML(conn, StringValueCStr(xml));
+    _E(netw == NULL, create_error(e_DefinitionError, "virNetworkDefineXML",
+                                  conn));
+
+    return network_new(netw, c);
+}
+
+#if HAVE_TYPE_VIRNODEDEVICEPTR
+extern VALUE nodedevice_new(virNodeDevicePtr s, VALUE conn);
+
+/*
+ * call-seq:
+ *   conn.num_of_nodedevices(cap=nil, flags=0) -> fixnum
+ *
+ * Call +virNodeNumOfDevices+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeNumOfDevices]
+ * to retrieve the number of node devices on this connection.
+ */
+static VALUE libvirt_conn_num_of_nodedevices(int argc, VALUE *argv, VALUE c) {
+    int result;
+    virConnectPtr conn = connect_get(c);
+    VALUE cap, flags;
+
+    rb_scan_args(argc, argv, "02", &cap, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    result = virNodeNumOfDevices(conn, get_string_or_nil(cap), NUM2UINT(flags));
+    _E(result < 0, create_error(e_RetrieveError, "virNodeNumOfDevices", conn));
+
+    return INT2NUM(result);
+}
+
+/*
+ * call-seq:
+ *   conn.list_nodedevices(cap=nil, flags=0) -> list
+ *
+ * Call +virNodeListDevices+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeListDevices]
+ * to retrieve a list of node device names on this connection.
+ */
+static VALUE libvirt_conn_list_nodedevices(int argc, VALUE *argv, VALUE c) {
+    int r, num;
+    virConnectPtr conn = connect_get(c);
+    VALUE cap, flags_val;
+    char *capstr;
+    char **names;
+    unsigned int flags;
+
+    rb_scan_args(argc, argv, "02", &cap, &flags_val);
+
+    if (NIL_P(flags_val))
+        flags = 0;
+    else
+        flags = NUM2UINT(flags_val);
+
+    capstr = get_string_or_nil(cap);
+
+    num = virNodeNumOfDevices(conn, capstr, 0);
+    _E(num < 0, create_error(e_RetrieveError, "virNodeNumOfDevices", conn));
+    if (num == 0)
+        /* if num is 0, don't call virNodeListDevices function */
+        return rb_ary_new2(num);
+
+    names = ALLOC_N(char *, num);
+    r = virNodeListDevices(conn, capstr, names, num, flags);
+    if (r < 0) {
+        xfree(names);
+        rb_exc_raise(create_error(e_RetrieveError, "virNodeListDevices", conn));
+    }
+
+    return gen_list(num, &names);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_nodedevice_by_name(name) -> Libvirt::NodeDevice
+ *
+ * Call +virNodeDeviceLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceLookupByName]
+ * to retrieve a nodedevice object by name.
+ */
+static VALUE libvirt_conn_lookup_nodedevice_by_name(VALUE c, VALUE name) {
+    virNodeDevicePtr nodedev;
+    virConnectPtr conn = connect_get(c);
+
+    nodedev = virNodeDeviceLookupByName(conn, StringValueCStr(name));
+    _E(nodedev == NULL, create_error(e_RetrieveError,
+                                     "virNodeDeviceLookupByName", conn));
+
+    return nodedevice_new(nodedev, c);
+
+}
+
+#if HAVE_VIRNODEDEVICECREATEXML
+/*
+ * call-seq:
+ *   conn.create_nodedevice_xml(xml, flags=0) -> Libvirt::NodeDevice
+ *
+ * Call +virNodeDeviceCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceCreateXML]
+ * to create a new node device from xml.
+ */
+static VALUE libvirt_conn_create_nodedevice_xml(int argc, VALUE *argv,
+                                                VALUE c) {
+    virNodeDevicePtr nodedev;
+    virConnectPtr conn = connect_get(c);
+    VALUE xml, flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    nodedev = virNodeDeviceCreateXML(conn, StringValueCStr(xml),
+                                     NUM2UINT(flags));
+    _E(nodedev == NULL, create_error(e_Error, "virNodeDeviceCreateXML", conn));
+
+    return nodedevice_new(nodedev, c);
+}
+#endif
+#endif
+
+#if HAVE_TYPE_VIRNWFILTERPTR
+extern VALUE nwfilter_new(virNWFilterPtr nw, VALUE conn);
+
+/*
+ * call-seq:
+ *   conn.num_of_nwfilters -> fixnum
+ *
+ * Call +virConnectNumOfNWFilters+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfNWFilters]
+ * to retrieve the number of network filters on this connection.
+ */
+static VALUE libvirt_conn_num_of_nwfilters(VALUE s) {
+    gen_conn_num_of(s, NWFilters);
+}
+
+/*
+ * call-seq:
+ *   conn.list_nwfilters -> list
+ *
+ * Call +virConnectListNWFilters+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListNWFilters]
+ * to retrieve a list of network filter names on this connection.
+ */
+static VALUE libvirt_conn_list_nwfilters(VALUE s) {
+    gen_conn_list_names(s, NWFilters);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_nwfilter_by_name(name) -> Libvirt::NWFilter
+ *
+ * Call +virNWFilterLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterLookupByName]
+ * to retrieve a network filter object by name.
+ */
+static VALUE libvirt_conn_lookup_nwfilter_by_name(VALUE c, VALUE name) {
+    virNWFilterPtr nwfilter;
+    virConnectPtr conn = connect_get(c);
+
+    nwfilter = virNWFilterLookupByName(conn, StringValueCStr(name));
+    _E(nwfilter == NULL, create_error(e_RetrieveError,
+                                      "virNWFilterLookupByName", conn));
+
+    return nwfilter_new(nwfilter, c);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_nwfilter_by_uuid(uuid) -> Libvirt::NWFilter
+ *
+ * Call +virNWFilterLookupByUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterLookupByUUIDString]
+ * to retrieve a network filter object by UUID.
+ */
+static VALUE libvirt_conn_lookup_nwfilter_by_uuid(VALUE c, VALUE uuid) {
+    virNWFilterPtr nwfilter;
+    virConnectPtr conn = connect_get(c);
+
+    nwfilter = virNWFilterLookupByUUIDString(conn, StringValueCStr(uuid));
+    _E(nwfilter == NULL, create_error(e_RetrieveError,
+                                      "virNWFilterLookupByUUIDString", conn));
+
+    return nwfilter_new(nwfilter, c);
+}
+
+/*
+ * call-seq:
+ *   conn.define_nwfilter_xml(xml) -> Libvirt::NWFilter
+ *
+ * Call +virNWFilterDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterDefineXML]
+ * to define a new network filter from xml.
+ */
+static VALUE libvirt_conn_define_nwfilter_xml(VALUE c, VALUE xml) {
+    virNWFilterPtr nwfilter;
+    virConnectPtr conn = connect_get(c);
+
+    nwfilter = virNWFilterDefineXML(conn, StringValueCStr(xml));
+    _E(nwfilter == NULL, create_error(e_DefinitionError, "virNWFilterDefineXML",
+                                      conn));
+
+    return nwfilter_new(nwfilter, c);
+}
+#endif
+
+#if HAVE_TYPE_VIRSECRETPTR
+extern VALUE secret_new(virSecretPtr s, VALUE conn);
+
+/*
+ * call-seq:
+ *   conn.num_of_secrets -> fixnum
+ *
+ * Call +virConnectNumOfSecrets+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfSecrets]
+ * to retrieve the number of secrets on this connection.
+ */
+static VALUE libvirt_conn_num_of_secrets(VALUE s) {
+    gen_conn_num_of(s, Secrets);
+}
+
+/*
+ * call-seq:
+ *   conn.list_secrets -> list
+ *
+ * Call +virConnectListSecrets+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListSecrets]
+ * to retrieve a list of secret UUIDs on this connection.
+ */
+static VALUE libvirt_conn_list_secrets(VALUE s) {
+    gen_conn_list_names(s, Secrets);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_secret_by_uuid(uuid) -> Libvirt::Secret
+ *
+ * Call +virSecretLookupByUUID+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretLookupByUUID]
+ * to retrieve a network object from uuid.
+ */
+static VALUE libvirt_conn_lookup_secret_by_uuid(VALUE c, VALUE uuid) {
+    virSecretPtr secret;
+    virConnectPtr conn = connect_get(c);
+
+    secret = virSecretLookupByUUIDString(conn, StringValueCStr(uuid));
+    _E(secret == NULL, create_error(e_RetrieveError, "virSecretLookupByUUID",
+                                    conn));
+
+    return secret_new(secret, c);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_secret_by_usage(usagetype, usageID) -> Libvirt::Secret
+ *
+ * Call +virSecretLookupByUsage+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretLookupByUsage]
+ * to retrieve a secret by usagetype.
+ */
+static VALUE libvirt_conn_lookup_secret_by_usage(VALUE c, VALUE usagetype,
+                                                 VALUE usageID) {
+    virSecretPtr secret;
+    virConnectPtr conn = connect_get(c);
+
+    secret = virSecretLookupByUsage(conn, NUM2UINT(usagetype),
+                                    StringValueCStr(usageID));
+    _E(secret == NULL, create_error(e_RetrieveError, "virSecretLookupByUsage",
+                                    conn));
+
+    return secret_new(secret, c);
+}
+
+/*
+ * call-seq:
+ *   conn.define_secret_xml(xml, flags=0) -> Libvirt::Secret
+ *
+ * Call +virSecretDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretDefineXML]
+ * to define a new secret from xml.
+ */
+static VALUE libvirt_conn_define_secret_xml(int argc, VALUE *argv, VALUE c) {
+    virSecretPtr secret;
+    virConnectPtr conn = connect_get(c);
+    VALUE xml, flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    secret = virSecretDefineXML(conn, StringValueCStr(xml), NUM2UINT(flags));
+    _E(secret == NULL, create_error(e_DefinitionError, "virSecretDefineXML",
+                                    conn));
+
+    return secret_new(secret, c);
+}
+#endif
+
+#if HAVE_TYPE_VIRSTORAGEPOOLPTR
+
+VALUE pool_new(virStoragePoolPtr n, VALUE conn);
+
+/*
+ * call-seq:
+ *   conn.list_storage_pools -> list
+ *
+ * Call +virConnectListStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListStoragePools]
+ * to retrieve a list of active storage pool names on this connection.
+ */
+static VALUE libvirt_conn_list_storage_pools(VALUE s) {
+    gen_conn_list_names(s, StoragePools);
+}
+
+/*
+ * call-seq:
+ *   conn.num_of_storage_pools -> fixnum
+ *
+ * Call +virConnectNumOfStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfStoragePools]
+ * to retrieve the number of active storage pools on this connection.
+ */
+static VALUE libvirt_conn_num_of_storage_pools(VALUE s) {
+    gen_conn_num_of(s, StoragePools);
+}
+
+/*
+ * call-seq:
+ *   conn.list_defined_storage_pools -> list
+ *
+ * Call +virConnectListDefinedStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectListDefinedStoragePools]
+ * to retrieve a list of inactive storage pool names on this connection.
+ */
+static VALUE libvirt_conn_list_defined_storage_pools(VALUE s) {
+    gen_conn_list_names(s, DefinedStoragePools);
+}
+
+/*
+ * call-seq:
+ *   conn.num_of_defined_storage_pools -> fixnum
+ *
+ * Call +virConnectNumOfDefinedStoragePools+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectNumOfDefinedStoragePools]
+ * to retrieve the number of inactive storage pools on this connection.
+ */
+static VALUE libvirt_conn_num_of_defined_storage_pools(VALUE s) {
+    gen_conn_num_of(s, DefinedStoragePools);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_storage_pool_by_name(name) -> Libvirt::StoragePool
+ *
+ * Call +virStoragePoolLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolLookupByName]
+ * to retrieve a storage pool object by name.
+ */
+static VALUE libvirt_conn_lookup_pool_by_name(VALUE c, VALUE name) {
+    virStoragePoolPtr pool;
+    virConnectPtr conn = connect_get(c);
+
+    pool = virStoragePoolLookupByName(conn, StringValueCStr(name));
+    _E(pool == NULL, create_error(e_RetrieveError, "virStoragePoolLookupByName",
+                                  conn));
+
+    return pool_new(pool, c);
+}
+
+/*
+ * call-seq:
+ *   conn.lookup_storage_pool_by_uuid(uuid) -> Libvirt::StoragePool
+ *
+ * Call +virStoragePoolLookupByUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolLookupByUUIDString]
+ * to retrieve a storage pool object by uuid.
+ */
+static VALUE libvirt_conn_lookup_pool_by_uuid(VALUE c, VALUE uuid) {
+    virStoragePoolPtr pool;
+    virConnectPtr conn = connect_get(c);
+
+    pool = virStoragePoolLookupByUUIDString(conn, StringValueCStr(uuid));
+    _E(pool == NULL, create_error(e_RetrieveError, "virStoragePoolLookupByUUID",
+                                  conn));
+
+    return pool_new(pool, c);
+}
+
+/*
+ * call-seq:
+ *   conn.create_storage_pool_xml(xml, flags=0) -> Libvirt::StoragePool
+ *
+ * Call +virStoragePoolCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolCreateXML]
+ * to start a new transient storage pool from xml.
+ */
+static VALUE libvirt_conn_create_pool_xml(int argc, VALUE *argv, VALUE c) {
+    virStoragePoolPtr pool;
+    virConnectPtr conn = connect_get(c);
+    VALUE xml, flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    pool = virStoragePoolCreateXML(conn, StringValueCStr(xml), NUM2UINT(flags));
+    _E(pool == NULL, create_error(e_Error, "virStoragePoolCreateXML", conn));
+
+    return pool_new(pool, c);
+}
+
+/*
+ * call-seq:
+ *   conn.define_storage_pool_xml(xml, flags=0) -> Libvirt::StoragePool
+ *
+ * Call +virStoragePoolDefineXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolDefineXML]
+ * to define a permanent storage pool from xml.
+ */
+static VALUE libvirt_conn_define_pool_xml(int argc, VALUE *argv, VALUE c) {
+    virStoragePoolPtr pool;
+    virConnectPtr conn = connect_get(c);
+    VALUE xml, flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    pool = virStoragePoolDefineXML(conn, StringValueCStr(xml), NUM2UINT(flags));
+    _E(pool == NULL, create_error(e_DefinitionError, "virStoragePoolDefineXML",
+                                  conn));
+
+    return pool_new(pool, c);
+}
+
+/*
+ * call-seq:
+ *   conn.discover_storage_pool_sources(type, srcSpec=nil, flags=0) -> string
+ *
+ * Call +virConnectFindStoragePoolSources+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectFindStoragePoolSources]
+ * to find the storage pool sources corresponding to type.
+ */
+static VALUE libvirt_conn_find_storage_pool_sources(int argc, VALUE *argv,
+                                                    VALUE c) {
+    VALUE type, srcSpec_val, flags;
+
+    rb_scan_args(argc, argv, "12", &type, &srcSpec_val, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virConnectFindStoragePoolSources, conn(c), 1,
+                    connect_get(c), StringValueCStr(type),
+                    get_string_or_nil(srcSpec_val), NUM2UINT(flags));
+}
+#endif
+
+#if HAVE_VIRCONNECTGETSYSINFO
+/*
+ * call-seq:
+ *   conn.sys_info(flags=0) -> string
+ *
+ * Call +virConnectGetSysinfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectGetSysinfo]
+ * to get machine-specific information about the hypervisor.  This may include
+ * data such as the host UUID, the BIOS version, etc.
+ */
+static VALUE libvirt_conn_get_sys_info(int argc, VALUE *argv, VALUE c) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virConnectGetSysinfo, conn(c), 1, connect_get(c),
+                    NUM2UINT(flags));
+}
+#endif
+
+#if HAVE_TYPE_VIRSTREAMPTR
+extern VALUE stream_new(virStreamPtr s, VALUE conn);
+
+/*
+ * call-seq:
+ *   conn.stream(flags=0) -> Libvirt::Stream
+ *
+ * Call +virStreamNew+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamNew]
+ * to create a new stream.
+ */
+static VALUE libvirt_conn_stream(int argc, VALUE *argv, VALUE c) {
+    VALUE flags;
+    virStreamPtr stream;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    stream = virStreamNew(connect_get(c), NUM2UINT(flags));
+
+    _E(stream == NULL, create_error(e_RetrieveError, "virStreamNew", conn(c)));
+
+    return stream_new(stream, c);
+}
+#endif
+
+#if HAVE_VIRINTERFACECHANGEBEGIN
+/*
+ * call-seq:
+ *   conn.interface_change_begin(flags=0) -> nil
+ *
+ * Call +virInterfaceChangeBegin+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceChangeBegin]
+ * to create a restore point for interface changes.  Once changes have been
+ * made, conn.interface_change_commit can be used to commit the result or
+ * conn.interface_change_rollback can be used to rollback to this restore point.
+ */
+static VALUE libvirt_conn_interface_change_begin(int argc, VALUE *argv,
+                                                 VALUE c) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    gen_call_void(virInterfaceChangeBegin, conn(c), connect_get(c),
+                  NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   conn.interface_change_commit(flags=0) -> nil
+ *
+ * Call +virInterfaceChangeCommit+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceChangeCommit]
+ * to commit the interface changes since the last conn.interface_change_begin.
+ */
+static VALUE libvirt_conn_interface_change_commit(int argc, VALUE *argv,
+                                                  VALUE c) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    gen_call_void(virInterfaceChangeCommit, conn(c), connect_get(c),
+                  NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   conn.interface_change_rollback(flags=0) -> nil
+ *
+ * Call +virInterfaceChangeRollback+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceChangeRollback]
+ * to rollback to the restore point saved by conn.interface_change_begin.
+ */
+static VALUE libvirt_conn_interface_change_rollback(int argc, VALUE *argv,
+                                                    VALUE c) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    gen_call_void(virInterfaceChangeRollback, conn(c), connect_get(c),
+                  NUM2UINT(flags));
+}
+#endif
+
+/*
+ * Class Libvirt::Connect
+ */
+void init_connect()
+{
+    c_connect = rb_define_class_under(m_libvirt, "Connect", rb_cObject);
+
+    /*
+     * Class Libvirt::Connect::Nodeinfo
+     */
+    c_node_info = rb_define_class_under(c_connect, "Nodeinfo", rb_cObject);
+    rb_define_attr(c_node_info, "model", 1, 0);
+    rb_define_attr(c_node_info, "memory", 1, 0);
+    rb_define_attr(c_node_info, "cpus", 1, 0);
+    rb_define_attr(c_node_info, "mhz", 1, 0);
+    rb_define_attr(c_node_info, "nodes", 1, 0);
+    rb_define_attr(c_node_info, "sockets", 1, 0);
+    rb_define_attr(c_node_info, "cores", 1, 0);
+    rb_define_attr(c_node_info, "threads", 1, 0);
+
+    /*
+     * Class Libvirt::Connect::NodeSecurityModel
+     */
+    c_node_security_model = rb_define_class_under(c_connect,
+                                                  "NodeSecurityModel",
+                                                  rb_cObject);
+    rb_define_attr(c_node_security_model, "model", 1, 0);
+    rb_define_attr(c_node_security_model, "doi", 1, 0);
+
+    rb_define_method(c_connect, "close", libvirt_conn_close, 0);
+    rb_define_method(c_connect, "closed?", libvirt_conn_closed_p, 0);
+    rb_define_method(c_connect, "type", libvirt_conn_type, 0);
+    rb_define_method(c_connect, "version", libvirt_conn_version, 0);
+#if HAVE_VIRCONNECTGETLIBVERSION
+    rb_define_method(c_connect, "libversion", libvirt_conn_libversion, 0);
+#endif
+    rb_define_method(c_connect, "hostname", libvirt_conn_hostname, 0);
+    rb_define_method(c_connect, "uri", libvirt_conn_uri, 0);
+    rb_define_method(c_connect, "max_vcpus", libvirt_conn_max_vcpus, -1);
+    rb_define_method(c_connect, "node_get_info", libvirt_conn_node_get_info, 0);
+    rb_define_method(c_connect, "node_free_memory",
+                     libvirt_conn_node_free_memory, 0);
+    rb_define_method(c_connect, "node_cells_free_memory",
+                     libvirt_conn_node_cells_free_memory, -1);
+#if HAVE_VIRNODEGETSECURITYMODEL
+    rb_define_method(c_connect, "node_get_security_model",
+                     libvirt_conn_node_get_security_model, 0);
+#endif
+#if HAVE_VIRCONNECTISENCRYPTED
+    rb_define_method(c_connect, "encrypted?", libvirt_conn_encrypted_p, 0);
+#endif
+#if HAVE_VIRCONNECTISSECURE
+    rb_define_method(c_connect, "secure?", libvirt_conn_secure_p, 0);
+#endif
+    rb_define_method(c_connect, "capabilities", libvirt_conn_capabilities, 0);
+
+#if HAVE_VIRCONNECTCOMPARECPU
+    rb_define_const(c_connect, "CPU_COMPARE_ERROR",
+                    INT2NUM(VIR_CPU_COMPARE_ERROR));
+    rb_define_const(c_connect, "CPU_COMPARE_INCOMPATIBLE",
+                    INT2NUM(VIR_CPU_COMPARE_INCOMPATIBLE));
+    rb_define_const(c_connect, "CPU_COMPARE_IDENTICAL",
+                    INT2NUM(VIR_CPU_COMPARE_IDENTICAL));
+    rb_define_const(c_connect, "CPU_COMPARE_SUPERSET",
+                    INT2NUM(VIR_CPU_COMPARE_SUPERSET));
+
+    rb_define_method(c_connect, "compare_cpu", libvirt_conn_compare_cpu, -1);
+#endif
+
+#if HAVE_VIRCONNECTBASELINECPU
+    rb_define_method(c_connect, "baseline_cpu", libvirt_conn_baseline_cpu, -1);
+#endif
+
+    /* In the libvirt development history, the events were
+     * first defined in commit 1509b8027fd0b73c30aeab443f81dd5a18d80544,
+     * then ADDED and REMOVED were renamed to DEFINED and UNDEFINED at
+     * the same time that the details were added
+     * (d3d54d2fc92e350f250eda26cee5d0342416a9cf).  What this means is that
+     * we have to check for HAVE_CONST_VIR_DOMAIN_EVENT_DEFINED and
+     * HAVE_CONST_VIR_DOMAIN_EVENT_STARTED to untangle these, and then we
+     * can make a decision for many of the events based on that.
+     */
+#if HAVE_CONST_VIR_DOMAIN_EVENT_DEFINED
+    rb_define_const(c_connect, "DOMAIN_EVENT_DEFINED",
+                    INT2NUM(VIR_DOMAIN_EVENT_DEFINED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_DEFINED_ADDED",
+                    INT2NUM(VIR_DOMAIN_EVENT_DEFINED_ADDED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_DEFINED_UPDATED",
+                    INT2NUM(VIR_DOMAIN_EVENT_DEFINED_UPDATED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_UNDEFINED",
+                    INT2NUM(VIR_DOMAIN_EVENT_UNDEFINED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_UNDEFINED_REMOVED",
+                    INT2NUM(VIR_DOMAIN_EVENT_UNDEFINED_REMOVED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STARTED_BOOTED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STARTED_BOOTED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STARTED_MIGRATED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STARTED_MIGRATED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STARTED_RESTORED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STARTED_RESTORED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_SUSPENDED_PAUSED",
+                    INT2NUM(VIR_DOMAIN_EVENT_SUSPENDED_PAUSED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_SUSPENDED_MIGRATED",
+                    INT2NUM(VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_RESUMED_UNPAUSED",
+                    INT2NUM(VIR_DOMAIN_EVENT_RESUMED_UNPAUSED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_RESUMED_MIGRATED",
+                    INT2NUM(VIR_DOMAIN_EVENT_RESUMED_MIGRATED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED_SHUTDOWN",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED_DESTROYED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED_DESTROYED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED_CRASHED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED_CRASHED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED_MIGRATED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED_MIGRATED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED_SAVED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED_SAVED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED_FAILED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED_FAILED));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_STARTED
+    rb_define_const(c_connect, "DOMAIN_EVENT_STARTED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STARTED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_SUSPENDED",
+                    INT2NUM(VIR_DOMAIN_EVENT_SUSPENDED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_RESUMED",
+                    INT2NUM(VIR_DOMAIN_EVENT_RESUMED));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED));
+#endif
+#if HAVE_TYPE_VIRDOMAINSNAPSHOTPTR
+    rb_define_const(c_connect, "DOMAIN_EVENT_STARTED_FROM_SNAPSHOT",
+                    INT2NUM(VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT));
+    rb_define_const(c_connect, "DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT",
+                    INT2NUM(VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_SUSPENDED_IOERROR
+    rb_define_const(c_connect, "DOMAIN_EVENT_SUSPENDED_IOERROR",
+                    INT2NUM(VIR_DOMAIN_EVENT_SUSPENDED_IOERROR));
+    rb_define_const(c_connect, "DOMAIN_EVENT_SUSPENDED_WATCHDOG",
+                    INT2NUM(VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_ID_WATCHDOG
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_WATCHDOG",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_WATCHDOG));
+    rb_define_const(c_connect, "DOMAIN_EVENT_WATCHDOG_NONE",
+                    INT2NUM(VIR_DOMAIN_EVENT_WATCHDOG_NONE));
+    rb_define_const(c_connect, "DOMAIN_EVENT_WATCHDOG_PAUSE",
+                    INT2NUM(VIR_DOMAIN_EVENT_WATCHDOG_PAUSE));
+    rb_define_const(c_connect, "DOMAIN_EVENT_WATCHDOG_RESET",
+                    INT2NUM(VIR_DOMAIN_EVENT_WATCHDOG_RESET));
+    rb_define_const(c_connect, "DOMAIN_EVENT_WATCHDOG_POWEROFF",
+                    INT2NUM(VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF));
+    rb_define_const(c_connect, "DOMAIN_EVENT_WATCHDOG_SHUTDOWN",
+                    INT2NUM(VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN));
+    rb_define_const(c_connect, "DOMAIN_EVENT_WATCHDOG_DEBUG",
+                    INT2NUM(VIR_DOMAIN_EVENT_WATCHDOG_DEBUG));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_ID_IO_ERROR
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_IO_ERROR",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_IO_ERROR));
+    rb_define_const(c_connect, "DOMAIN_EVENT_IO_ERROR_NONE",
+                    INT2NUM(VIR_DOMAIN_EVENT_IO_ERROR_NONE));
+    rb_define_const(c_connect, "DOMAIN_EVENT_IO_ERROR_PAUSE",
+                    INT2NUM(VIR_DOMAIN_EVENT_IO_ERROR_PAUSE));
+    rb_define_const(c_connect, "DOMAIN_EVENT_IO_ERROR_REPORT",
+                    INT2NUM(VIR_DOMAIN_EVENT_IO_ERROR_REPORT));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_ID_GRAPHICS
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_GRAPHICS",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_GRAPHICS));
+    rb_define_const(c_connect, "DOMAIN_EVENT_GRAPHICS_CONNECT",
+                    INT2NUM(VIR_DOMAIN_EVENT_GRAPHICS_CONNECT));
+    rb_define_const(c_connect, "DOMAIN_EVENT_GRAPHICS_INITIALIZE",
+                    INT2NUM(VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE));
+    rb_define_const(c_connect, "DOMAIN_EVENT_GRAPHICS_DISCONNECT",
+                    INT2NUM(VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT));
+    rb_define_const(c_connect, "DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4",
+                    INT2NUM(VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4));
+    rb_define_const(c_connect, "DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6",
+                    INT2NUM(VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6));
+#endif
+#if HAVE_VIRCONNECTDOMAINEVENTREGISTERANY
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_LIFECYCLE",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_LIFECYCLE));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_ID_REBOOT
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_REBOOT",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_REBOOT));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_ID_RTC_CHANGE
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_RTC_CHANGE",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_RTC_CHANGE));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_IO_ERROR_REASON",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON));
+#endif
+
+#if HAVE_CONST_VIR_DOMAIN_EVENT_ID_CONTROL_ERROR
+    rb_define_const(c_connect, "DOMAIN_EVENT_ID_CONTROL_ERROR",
+                    INT2NUM(VIR_DOMAIN_EVENT_ID_CONTROL_ERROR));
+#endif
+
+#if HAVE_VIRCONNECTDOMAINEVENTREGISTER
+    rb_define_method(c_connect, "domain_event_register",
+                     libvirt_conn_domain_event_register, -1);
+    rb_define_method(c_connect, "domain_event_deregister",
+                     libvirt_conn_domain_event_deregister, 0);
+#endif
+
+#if HAVE_VIRCONNECTDOMAINEVENTREGISTERANY
+    rb_define_method(c_connect, "domain_event_register_any",
+                     libvirt_conn_domain_event_register_any, -1);
+    rb_define_method(c_connect, "domain_event_deregister_any",
+                     libvirt_conn_domain_event_deregister_any, 1);
+#endif
+
+    /* Domain creation/lookup */
+    rb_define_method(c_connect, "num_of_domains",
+                     libvirt_conn_num_of_domains, 0);
+    rb_define_method(c_connect, "list_domains", libvirt_conn_list_domains, 0);
+    rb_define_method(c_connect, "num_of_defined_domains",
+                     libvirt_conn_num_of_defined_domains, 0);
+    rb_define_method(c_connect, "list_defined_domains",
+                     libvirt_conn_list_defined_domains, 0);
+    rb_define_method(c_connect, "create_domain_linux",
+                     libvirt_conn_create_linux, -1);
+#if HAVE_VIRDOMAINCREATEXML
+    rb_define_method(c_connect, "create_domain_xml",
+                     libvirt_conn_create_xml, -1);
+#endif
+    rb_define_method(c_connect, "lookup_domain_by_name",
+                     libvirt_conn_lookup_domain_by_name, 1);
+    rb_define_method(c_connect, "lookup_domain_by_id",
+                     libvirt_conn_lookup_domain_by_id, 1);
+    rb_define_method(c_connect, "lookup_domain_by_uuid",
+                     libvirt_conn_lookup_domain_by_uuid, 1);
+    rb_define_method(c_connect, "define_domain_xml",
+                     libvirt_conn_define_domain_xml, 1);
+
+#if HAVE_VIRCONNECTDOMAINXMLFROMNATIVE
+    rb_define_method(c_connect, "domain_xml_from_native",
+                     libvirt_conn_domain_xml_from_native, -1);
+#endif
+#if HAVE_VIRCONNECTDOMAINXMLTONATIVE
+    rb_define_method(c_connect, "domain_xml_to_native",
+                     libvirt_conn_domain_xml_to_native, -1);
+#endif
+
+#if HAVE_TYPE_VIRINTERFACEPTR
+    /* Interface lookup/creation methods */
+    rb_define_method(c_connect, "num_of_interfaces",
+                     libvirt_conn_num_of_interfaces, 0);
+    rb_define_method(c_connect, "list_interfaces",
+                     libvirt_conn_list_interfaces, 0);
+    rb_define_method(c_connect, "num_of_defined_interfaces",
+                     libvirt_conn_num_of_defined_interfaces, 0);
+    rb_define_method(c_connect, "list_defined_interfaces",
+                     libvirt_conn_list_defined_interfaces, 0);
+    rb_define_method(c_connect, "lookup_interface_by_name",
+                     libvirt_conn_lookup_interface_by_name, 1);
+    rb_define_method(c_connect, "lookup_interface_by_mac",
+                     libvirt_conn_lookup_interface_by_mac, 1);
+    rb_define_method(c_connect, "define_interface_xml",
+                     libvirt_conn_define_interface_xml, -1);
+#endif
+
+    /* Network lookup/creation methods */
+    rb_define_method(c_connect, "num_of_networks",
+                     libvirt_conn_num_of_networks, 0);
+    rb_define_method(c_connect, "list_networks", libvirt_conn_list_networks, 0);
+    rb_define_method(c_connect, "num_of_defined_networks",
+                     libvirt_conn_num_of_defined_networks, 0);
+    rb_define_method(c_connect, "list_defined_networks",
+                     libvirt_conn_list_defined_networks, 0);
+    rb_define_method(c_connect, "lookup_network_by_name",
+                     libvirt_conn_lookup_network_by_name, 1);
+    rb_define_method(c_connect, "lookup_network_by_uuid",
+                     libvirt_conn_lookup_network_by_uuid, 1);
+    rb_define_method(c_connect, "create_network_xml",
+                     libvirt_conn_create_network_xml, 1);
+    rb_define_method(c_connect, "define_network_xml",
+                     libvirt_conn_define_network_xml, 1);
+
+    /* Node device lookup/creation methods */
+#if HAVE_TYPE_VIRNODEDEVICEPTR
+    rb_define_method(c_connect, "num_of_nodedevices",
+                     libvirt_conn_num_of_nodedevices, -1);
+    rb_define_method(c_connect, "list_nodedevices",
+                     libvirt_conn_list_nodedevices, -1);
+    rb_define_method(c_connect, "lookup_nodedevice_by_name",
+                     libvirt_conn_lookup_nodedevice_by_name, 1);
+#if HAVE_VIRNODEDEVICECREATEXML
+    rb_define_method(c_connect, "create_nodedevice_xml",
+                     libvirt_conn_create_nodedevice_xml, -1);
+#endif
+#endif
+
+#if HAVE_TYPE_VIRNWFILTERPTR
+    /* NWFilter lookup/creation methods */
+    rb_define_method(c_connect, "num_of_nwfilters",
+                     libvirt_conn_num_of_nwfilters, 0);
+    rb_define_method(c_connect, "list_nwfilters",
+                     libvirt_conn_list_nwfilters, 0);
+    rb_define_method(c_connect, "lookup_nwfilter_by_name",
+                     libvirt_conn_lookup_nwfilter_by_name, 1);
+    rb_define_method(c_connect, "lookup_nwfilter_by_uuid",
+                     libvirt_conn_lookup_nwfilter_by_uuid, 1);
+    rb_define_method(c_connect, "define_nwfilter_xml",
+                     libvirt_conn_define_nwfilter_xml, 1);
+#endif
+
+#if HAVE_TYPE_VIRSECRETPTR
+    /* Secret lookup/creation methods */
+    rb_define_method(c_connect, "num_of_secrets",
+                     libvirt_conn_num_of_secrets, 0);
+    rb_define_method(c_connect, "list_secrets",
+                     libvirt_conn_list_secrets, 0);
+    rb_define_method(c_connect, "lookup_secret_by_uuid",
+                     libvirt_conn_lookup_secret_by_uuid, 1);
+    rb_define_method(c_connect, "lookup_secret_by_usage",
+                     libvirt_conn_lookup_secret_by_usage, 2);
+    rb_define_method(c_connect, "define_secret_xml",
+                     libvirt_conn_define_secret_xml, -1);
+#endif
+
+#if HAVE_TYPE_VIRSTORAGEPOOLPTR
+    /* StoragePool lookup/creation methods */
+    rb_define_method(c_connect, "num_of_storage_pools",
+                     libvirt_conn_num_of_storage_pools, 0);
+    rb_define_method(c_connect, "list_storage_pools",
+                     libvirt_conn_list_storage_pools, 0);
+    rb_define_method(c_connect, "num_of_defined_storage_pools",
+                     libvirt_conn_num_of_defined_storage_pools, 0);
+    rb_define_method(c_connect, "list_defined_storage_pools",
+                     libvirt_conn_list_defined_storage_pools, 0);
+    rb_define_method(c_connect, "lookup_storage_pool_by_name",
+                     libvirt_conn_lookup_pool_by_name, 1);
+    rb_define_method(c_connect, "lookup_storage_pool_by_uuid",
+                     libvirt_conn_lookup_pool_by_uuid, 1);
+    rb_define_method(c_connect, "create_storage_pool_xml",
+                     libvirt_conn_create_pool_xml, -1);
+    rb_define_method(c_connect, "define_storage_pool_xml",
+                     libvirt_conn_define_pool_xml, -1);
+    rb_define_method(c_connect, "discover_storage_pool_sources",
+                     libvirt_conn_find_storage_pool_sources, -1);
+#endif
+
+#if HAVE_VIRCONNECTGETSYSINFO
+    rb_define_method(c_connect, "sys_info", libvirt_conn_get_sys_info, -1);
+#endif
+#if HAVE_TYPE_VIRSTREAMPTR
+    rb_define_method(c_connect, "stream", libvirt_conn_stream, -1);
+#endif
+
+#if HAVE_VIRINTERFACECHANGEBEGIN
+    rb_define_method(c_connect, "interface_change_begin",
+                     libvirt_conn_interface_change_begin, -1);
+    rb_define_method(c_connect, "interface_change_commit",
+                     libvirt_conn_interface_change_commit, -1);
+    rb_define_method(c_connect, "interface_change_rollback",
+                     libvirt_conn_interface_change_rollback, -1);
+#endif
+}
diff --git a/ext/libvirt/connect.h b/ext/libvirt/connect.h
new file mode 100644
index 0000000..c64428c
--- /dev/null
+++ b/ext/libvirt/connect.h
@@ -0,0 +1,11 @@
+#ifndef CONNECT_H
+#define CONNECT_H
+
+void init_connect();
+
+virConnectPtr conn(VALUE s);
+VALUE connect_new(virConnectPtr p);
+virConnectPtr connect_get(VALUE s);
+VALUE conn_attr(VALUE s);
+
+#endif
diff --git a/ext/libvirt/domain.c b/ext/libvirt/domain.c
new file mode 100644
index 0000000..d4a9236
--- /dev/null
+++ b/ext/libvirt/domain.c
@@ -0,0 +1,2651 @@
+/*
+ * domain.c: virDomain methods
+ *
+ * Copyright (C) 2007,2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <stdint.h>
+#include <ruby.h>
+#include <st.h>
+#include <libvirt/libvirt.h>
+#if HAVE_VIRDOMAINQEMUMONITORCOMMAND
+#include <libvirt/libvirt-qemu.h>
+#endif
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+#include "stream.h"
+
+#ifndef HAVE_TYPE_VIRTYPEDPARAMETERPTR
+#define VIR_TYPED_PARAM_INT VIR_DOMAIN_SCHED_FIELD_INT
+#define VIR_TYPED_PARAM_UINT VIR_DOMAIN_SCHED_FIELD_UINT
+#define VIR_TYPED_PARAM_LLONG VIR_DOMAIN_SCHED_FIELD_LLONG
+#define VIR_TYPED_PARAM_ULLONG VIR_DOMAIN_SCHED_FIELD_ULLONG
+#define VIR_TYPED_PARAM_DOUBLE VIR_DOMAIN_SCHED_FIELD_DOUBLE
+#define VIR_TYPED_PARAM_BOOLEAN VIR_DOMAIN_SCHED_FIELD_BOOLEAN
+
+#define VIR_TYPED_PARAM_FIELD_LENGTH 80
+typedef struct _virTypedParameter virTypedParameter;
+struct _virTypedParameter {
+    char field[VIR_TYPED_PARAM_FIELD_LENGTH];  /* parameter name */
+    int type;   /* parameter type, virTypedParameterType */
+    union {
+        int i;                      /* type is INT */
+        unsigned int ui;            /* type is UINT */
+        long long int l;            /* type is LLONG */
+        unsigned long long int ul;  /* type is ULLONG */
+        double d;                   /* type is DOUBLE */
+        char b;                     /* type is BOOLEAN */
+    } value; /* parameter value */
+};
+typedef virTypedParameter *virTypedParameterPtr;
+
+#endif
+
+static VALUE c_domain;
+static VALUE c_domain_info;
+static VALUE c_domain_ifinfo;
+static VALUE c_domain_security_label;
+static VALUE c_domain_block_stats;
+#if HAVE_TYPE_VIRDOMAINBLOCKINFOPTR
+static VALUE c_domain_block_info;
+#endif
+#if HAVE_TYPE_VIRDOMAINMEMORYSTATPTR
+static VALUE c_domain_memory_stats;
+#endif
+#if HAVE_TYPE_VIRDOMAINSNAPSHOTPTR
+static VALUE c_domain_snapshot;
+#endif
+#if HAVE_TYPE_VIRDOMAINJOBINFOPTR
+static VALUE c_domain_job_info;
+#endif
+static VALUE c_domain_vcpuinfo;
+
+static void domain_free(void *d) {
+    generic_free(Domain, d);
+}
+
+VALUE domain_new(virDomainPtr d, VALUE conn) {
+    return generic_new(c_domain, d, conn, domain_free);
+}
+
+virDomainPtr domain_get(VALUE s) {
+    generic_get(Domain, s);
+}
+
+/*
+ * call-seq:
+ *   dom.migrate(dconn, flags=0, dname=nil, uri=nil, bandwidth=0) -> Libvirt::Domain
+ *
+ * Call +virDomainMigrate+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMigrate]
+ * to migrate a domain from the host on this connection to the connection
+ * referenced in dconn.
+ */
+static VALUE libvirt_dom_migrate(int argc, VALUE *argv, VALUE s) {
+    VALUE dconn, flags, dname_val, uri_val, bandwidth;
+    virDomainPtr ddom = NULL;
+
+    rb_scan_args(argc, argv, "14", &dconn, &flags, &dname_val, &uri_val,
+                 &bandwidth);
+
+    if (NIL_P(bandwidth))
+        bandwidth = INT2NUM(0);
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    ddom = virDomainMigrate(domain_get(s), conn(dconn), NUM2ULONG(flags),
+                            get_string_or_nil(dname_val),
+                            get_string_or_nil(uri_val), NUM2ULONG(bandwidth));
+
+    _E(ddom == NULL, create_error(e_Error, "virDomainMigrate", conn(s)));
+
+    return domain_new(ddom, dconn);
+}
+
+#if HAVE_VIRDOMAINMIGRATETOURI
+/*
+ * call-seq:
+ *   dom.migrate_to_uri(duri, flags=0, dname=nil, bandwidth=0) -> nil
+ *
+ * Call +virDomainMigrateToURI+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMigrateToURI]
+ * to migrate a domain from the host on this connection to the host whose
+ * libvirt URI is duri.
+ */
+static VALUE libvirt_dom_migrate_to_uri(int argc, VALUE *argv, VALUE s) {
+    VALUE duri, flags, dname, bandwidth;
+
+    rb_scan_args(argc, argv, "13", &duri, &flags, &dname, &bandwidth);
+
+    if (NIL_P(bandwidth))
+        bandwidth = INT2NUM(0);
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainMigrateToURI, conn(s), domain_get(s),
+                  StringValueCStr(duri), NUM2ULONG(flags),
+                  get_string_or_nil(dname), NUM2ULONG(bandwidth));
+}
+#endif
+
+#if HAVE_VIRDOMAINMIGRATESETMAXDOWNTIME
+/*
+ * call-seq:
+ *   dom.migrate_set_max_downtime(downtime, flags=0) -> nil
+ *
+ * Call +virDomainMigrateSetMaxDowntime+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMigrateSetMaxDowntime]
+ * to set the maximum downtime desired for live migration.
+ */
+static VALUE libvirt_dom_migrate_set_max_downtime(int argc, VALUE *argv,
+                                                  VALUE s) {
+    VALUE downtime, flags;
+
+    rb_scan_args(argc, argv, "11", &downtime, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainMigrateSetMaxDowntime, conn(s), domain_get(s),
+                  NUM2ULL(downtime), NUM2UINT(flags));
+}
+#endif
+
+#if HAVE_VIRDOMAINMIGRATE2
+/*
+ * call-seq:
+ *   dom.migrate2(dconn, dxml=nil, flags=0, dname=nil, uri=nil, bandwidth=0) -> Libvirt::Domain
+ *
+ * Call +virDomainMigrate2+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMigrate2]
+ * to migrate a domain from the host on this connection to the connection
+ * referenced in dconn.
+ */
+static VALUE libvirt_dom_migrate2(int argc, VALUE *argv, VALUE s) {
+    VALUE dconn, dxml, flags, dname_val, uri_val, bandwidth;
+    virDomainPtr ddom = NULL;
+
+    rb_scan_args(argc, argv, "15", &dconn, &dxml, &flags, &dname_val, &uri_val,
+                 &bandwidth);
+
+    if (NIL_P(bandwidth))
+        bandwidth = INT2NUM(0);
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    ddom = virDomainMigrate2(domain_get(s), conn(dconn),
+                             get_string_or_nil(dxml), NUM2ULONG(flags),
+                             get_string_or_nil(dname_val),
+                             get_string_or_nil(uri_val), NUM2ULONG(bandwidth));
+
+    _E(ddom == NULL, create_error(e_Error, "virDomainMigrate2", conn(s)));
+
+    return domain_new(ddom, dconn);
+}
+
+/*
+ * call-seq:
+ *   dom.migrate_to_uri2(duri=nil, migrate_uri=nil, dxml=nil, flags=0, dname=nil, bandwidth=0) -> nil
+ *
+ * Call +virDomainMigrateToURI2+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMigrateToURI2]
+ * to migrate a domain from the host on this connection to the host whose
+ * libvirt URI is duri.
+ */
+static VALUE libvirt_dom_migrate_to_uri2(int argc, VALUE *argv, VALUE s) {
+    VALUE duri, migrate_uri, dxml, flags, dname, bandwidth;
+
+    rb_scan_args(argc, argv, "06", &duri, &migrate_uri, &dxml, &flags, &dname,
+                 &bandwidth);
+
+    if (NIL_P(bandwidth))
+        bandwidth = INT2NUM(0);
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainMigrateToURI2, conn(s), domain_get(s),
+                  get_string_or_nil(duri), get_string_or_nil(migrate_uri),
+                  get_string_or_nil(dxml), NUM2ULONG(flags),
+                  get_string_or_nil(dname), NUM2ULONG(bandwidth));
+}
+
+/*
+ * call-seq:
+ *   dom.migrate_set_max_speed(bandwidth, flags=0) -> nil
+ *
+ * Call +virDomainMigrateSetMaxSpeed+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMigrateSetMaxSpeed]
+ * to set the maximum bandwidth allowed for live migration.
+ */
+static VALUE libvirt_dom_migrate_set_max_speed(int argc, VALUE *argv, VALUE s) {
+    VALUE bandwidth, flags;
+
+    rb_scan_args(argc, argv, "11", &bandwidth, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainMigrateSetMaxSpeed, conn(s), domain_get(s),
+                  NUM2ULONG(bandwidth), NUM2UINT(flags));
+}
+#endif
+
+/*
+ * call-seq:
+ *   dom.shutdown -> nil
+ *
+ * Call +virDomainShutdown+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainShutdown]
+ * to do a soft shutdown of the domain.  The mechanism for doing the shutdown
+ * is hypervisor specific, and may require software running inside the domain
+ * to succeed.
+ */
+static VALUE libvirt_dom_shutdown(VALUE s) {
+    gen_call_void(virDomainShutdown, conn(s), domain_get(s));
+}
+
+/*
+ * call-seq:
+ *   dom.reboot(flags=0) -> nil
+ *
+ * Call +virDomainReboot+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainReboot]
+ * to do a reboot of the domain.
+ */
+static VALUE libvirt_dom_reboot(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainReboot, conn(s), domain_get(s), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.destroy -> nil
+ *
+ * Call +virDomainDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainDestroy]
+ * to do a hard power-off of the domain.
+ */
+static VALUE libvirt_dom_destroy(VALUE s) {
+    gen_call_void(virDomainDestroy, conn(s), domain_get(s));
+}
+
+/*
+ * call-seq:
+ *   dom.suspend -> nil
+ *
+ * Call +virDomainSuspend+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSuspend]
+ * to stop the domain from executing.  The domain will still continue to
+ * consume memory, but will not take any CPU time.
+ */
+static VALUE libvirt_dom_suspend(VALUE s) {
+    gen_call_void(virDomainSuspend, conn(s), domain_get(s));
+}
+
+/*
+ * call-seq:
+ *   dom.resume -> nil
+ *
+ * Call +virDomainResume+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainResume]
+ * to resume a suspended domain.  After this call the domain will start
+ * consuming CPU resources again.
+ */
+static VALUE libvirt_dom_resume(VALUE s) {
+    gen_call_void(virDomainResume, conn(s), domain_get(s));
+}
+
+/*
+ * call-seq:
+ *   dom.save(filename) -> nil
+ *
+ * Call +virDomainSave+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSave]
+ * to save the domain state to filename.  After this call, the domain will no
+ * longer be consuming any resources.
+ */
+static VALUE libvirt_dom_save(VALUE s, VALUE to) {
+    gen_call_void(virDomainSave, conn(s), domain_get(s), StringValueCStr(to));
+}
+
+#if HAVE_VIRDOMAINMANAGEDSAVE
+/*
+ * call-seq:
+ *   dom.managed_save(flags=0) -> nil
+ *
+ * Call +virDomainManagedSave+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainManagedSave]
+ * to do a managed save of the domain.  The domain will be saved to a place
+ * of libvirt's choosing.
+ */
+static VALUE libvirt_dom_managed_save(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainManagedSave, conn(s), domain_get(s),
+                  NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.has_managed_save?(flags=0) -> [True|False]
+ *
+ * Call +virDomainHasManagedSaveImage+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainHasManagedSaveImage]
+ * to determine if a particular domain has a managed save image.
+ */
+static VALUE libvirt_dom_has_managed_save(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_truefalse(virDomainHasManagedSaveImage, conn(s), domain_get(s),
+                       NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.managed_save_remove(flags=0) -> nil
+ *
+ * Call +virDomainManagedSaveRemove+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainManagedSaveRemove]
+ * to remove the managed save image for a domain.
+ */
+static VALUE libvirt_dom_managed_save_remove(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainManagedSaveRemove, conn(s), domain_get(s),
+                  NUM2UINT(flags));
+}
+#endif
+
+/*
+ * call-seq:
+ *   dom.core_dump(filename, flags=0) -> nil
+ *
+ * Call +virDomainCoreDump+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCoreDump]
+ * to do a full memory dump of the domain to filename.
+ */
+static VALUE libvirt_dom_core_dump(int argc, VALUE *argv, VALUE s) {
+    VALUE to, flags;
+
+    rb_scan_args(argc, argv, "11", &to, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainCoreDump, conn(s), domain_get(s),
+                  StringValueCStr(to), NUM2INT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.restore(filename) -> nil
+ *
+ * Call +virDomainRestore+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainRestore]
+ * to restore the domain from the filename.
+ */
+static VALUE libvirt_dom_restore(VALUE s, VALUE from) {
+    gen_call_void(virDomainRestore, conn(s), connect_get(s),
+                  StringValueCStr(from));
+}
+
+/*
+ * call-seq:
+ *   Libvirt::Domain::restore(conn, filename) -> nil
+ *
+ * Call +virDomainRestore+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainRestore]
+ * to restore the domain from the filename.
+ */
+static VALUE libvirt_dom_s_restore(VALUE klass, VALUE c, VALUE from) {
+    gen_call_void(virDomainRestore, conn(c), connect_get(c),
+                  StringValueCStr(from));
+}
+
+/*
+ * call-seq:
+ *   dom.info -> Libvirt::Domain::Info
+ *
+ * Call +virDomainGetInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetInfo]
+ * to retrieve domain information.
+ */
+static VALUE libvirt_dom_info(VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    virDomainInfo info;
+    int r;
+    VALUE result;
+
+    r = virDomainGetInfo(dom, &info);
+    _E(r < 0, create_error(e_RetrieveError, "virDomainGetInfo", conn(s)));
+
+    result = rb_class_new_instance(0, NULL, c_domain_info);
+    rb_iv_set(result, "@state", CHR2FIX(info.state));
+    rb_iv_set(result, "@max_mem", ULONG2NUM(info.maxMem));
+    rb_iv_set(result, "@memory", ULONG2NUM(info.memory));
+    rb_iv_set(result, "@nr_virt_cpu", INT2NUM((int) info.nrVirtCpu));
+    rb_iv_set(result, "@cpu_time", ULL2NUM(info.cpuTime));
+
+    return result;
+}
+
+#if HAVE_VIRDOMAINGETSECURITYLABEL
+/*
+ * call-seq:
+ *   dom.security_label -> Libvirt::Domain::SecurityLabel
+ *
+ * Call +virDomainGetSecurityLabel+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetSecurityLabel]
+ * to retrieve the security label applied to this domain.
+ */
+static VALUE libvirt_dom_security_label(VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    virSecurityLabel seclabel;
+    int r;
+    VALUE result;
+
+    r = virDomainGetSecurityLabel(dom, &seclabel);
+    _E(r < 0, create_error(e_RetrieveError, "virDomainGetSecurityLabel",
+                           conn(s)));
+
+    result = rb_class_new_instance(0, NULL, c_domain_security_label);
+    rb_iv_set(result, "@label", rb_str_new2(seclabel.label));
+    rb_iv_set(result, "@enforcing", INT2NUM(seclabel.enforcing));
+
+    return result;
+}
+#endif
+
+/*
+ * call-seq:
+ *   dom.block_stats(path) -> Libvirt::Domain::BlockStats
+ *
+ * Call +virDomainBlockStats+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainBlockStats]
+ * to retrieve statistics about domain block device path.
+ */
+static VALUE libvirt_dom_block_stats(VALUE s, VALUE path) {
+    virDomainPtr dom = domain_get(s);
+    virDomainBlockStatsStruct stats;
+    int r;
+    VALUE result;
+
+    r = virDomainBlockStats(dom, StringValueCStr(path), &stats, sizeof(stats));
+    _E(r < 0, create_error(e_RetrieveError, "virDomainBlockStats", conn(s)));
+
+    result = rb_class_new_instance(0, NULL, c_domain_block_stats);
+    rb_iv_set(result, "@rd_req", LL2NUM(stats.rd_req));
+    rb_iv_set(result, "@rd_bytes", LL2NUM(stats.rd_bytes));
+    rb_iv_set(result, "@wr_req", LL2NUM(stats.wr_req));
+    rb_iv_set(result, "@wr_bytes", LL2NUM(stats.wr_bytes));
+    rb_iv_set(result, "@errs", LL2NUM(stats.errs));
+
+    return result;
+}
+
+#if HAVE_TYPE_VIRDOMAINMEMORYSTATPTR
+/*
+ * call-seq:
+ *   dom.memory_stats(flags=0) -> [ Libvirt::Domain::MemoryStats ]
+ *
+ * Call +virDomainMemoryStats+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMemoryStats]
+ * to retrieve statistics about the amount of memory consumed by a domain.
+ */
+static VALUE libvirt_dom_memory_stats(int argc, VALUE *argv, VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    virDomainMemoryStatStruct stats[6];
+    int r;
+    VALUE result;
+    VALUE flags;
+    VALUE tmp;
+    int i;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    r = virDomainMemoryStats(dom, stats, 6, NUM2UINT(flags));
+    _E(r < 0, create_error(e_RetrieveError, "virDomainMemoryStats", conn(s)));
+
+    /* FIXME: the right rubyish way to have done this would have been to
+     * create a hash with the values, something like:
+     *
+     * { 'SWAP_IN' => 0, 'SWAP_OUT' => 98, 'MAJOR_FAULT' => 45,
+     *   'MINOR_FAULT' => 55, 'UNUSED' => 455, 'AVAILABLE' => 98 }
+     *
+     * Unfortunately this has already been released with the array version
+     * so we have to maintain compatibility with that.  We should probably add
+     * a new memory_stats-like call that properly creates the hash.
+     */
+    result = rb_ary_new2(r);
+    for (i=0; i<r; i++) {
+        tmp = rb_class_new_instance(0, NULL, c_domain_memory_stats);
+        rb_iv_set(tmp, "@tag", INT2NUM(stats[i].tag));
+        rb_iv_set(tmp, "@val", ULL2NUM(stats[i].val));
+
+        rb_ary_push(result, tmp);
+    }                                           \
+
+    return result;
+}
+#endif
+
+#if HAVE_TYPE_VIRDOMAINBLOCKINFOPTR
+/*
+ * call-seq:
+ *   dom.blockinfo(path, flags=0) -> Libvirt::Domain::BlockInfo
+ *
+ * Call +virDomainGetBlockInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetBlockInfo]
+ * to retrieve information about the backing file path for the domain.
+ */
+static VALUE libvirt_dom_block_info(int argc, VALUE *argv, VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    virDomainBlockInfo info;
+    int r;
+    VALUE result;
+    VALUE flags;
+    VALUE path;
+
+    rb_scan_args(argc, argv, "11", &path, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    r = virDomainGetBlockInfo(dom, StringValueCStr(path), &info,
+                              NUM2UINT(flags));
+    _E(r < 0, create_error(e_RetrieveError, "virDomainGetBlockInfo", conn(s)));
+
+    result = rb_class_new_instance(0, NULL, c_domain_block_info);
+    rb_iv_set(result, "@capacity", ULL2NUM(info.capacity));
+    rb_iv_set(result, "@allocation", ULL2NUM(info.allocation));
+    rb_iv_set(result, "@physical", ULL2NUM(info.physical));
+
+    return result;
+}
+#endif
+
+#if HAVE_VIRDOMAINBLOCKPEEK
+/*
+ * call-seq:
+ *   dom.block_peek(path, offset, size, flags=0) -> string
+ *
+ * Call +virDomainBlockPeek+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainBlockPeek]
+ * to read size number of bytes, starting at offset offset from domain backing
+ * file path.  Due to limitations of the libvirt remote protocol, the user
+ * should never request more than 64k bytes.
+ */
+static VALUE libvirt_dom_block_peek(int argc, VALUE *argv, VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    VALUE path_val, offset_val, size_val, flags_val;
+    char *buffer;
+    int r;
+    VALUE ret;
+    char *path;
+    unsigned int size, flags;
+    unsigned long long offset;
+    struct rb_str_new_arg args;
+    int exception = 0;
+
+    rb_scan_args(argc, argv, "31", &path_val, &offset_val, &size_val,
+                 &flags_val);
+
+    if (NIL_P(flags_val))
+        flags_val = INT2NUM(0);
+
+    path = StringValueCStr(path_val);
+    offset = NUM2ULL(offset_val);
+    size = NUM2UINT(size_val);
+    flags = NUM2UINT(flags_val);
+
+    buffer = ALLOC_N(char, size);
+
+    r = virDomainBlockPeek(dom, path, offset, size, buffer, flags);
+
+    if (r < 0) {
+        xfree(buffer);
+        rb_exc_raise(create_error(e_RetrieveError, "virDomainBlockPeek",
+                                  conn(s)));
+    }
+
+    args.val = buffer;
+    args.size = size;
+    ret = rb_protect(rb_str_new_wrap, (VALUE)&args, &exception);
+    xfree(buffer);
+    if (exception)
+        rb_jump_tag(exception);
+
+    return ret;
+}
+#endif
+
+#if HAVE_VIRDOMAINMEMORYPEEK
+/*
+ * call-seq:
+ *   dom.memory_peek(start, size, flags=Libvirt::Domain::MEMORY_VIRTUAL) -> string
+ *
+ * Call +virDomainMemoryPeek+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainMemoryPeek]
+ * to read size number of bytes from offset start from the domain memory.
+ * Due to limitations of the libvirt remote protocol, the user
+ * should never request more than 64k bytes.
+ */
+static VALUE libvirt_dom_memory_peek(int argc, VALUE *argv, VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    VALUE start_val, size_val, flags_val;
+    char *buffer;
+    int r;
+    VALUE ret;
+    unsigned int size, flags;
+    unsigned long long start;
+    struct rb_str_new_arg args;
+    int exception = 0;
+
+    rb_scan_args(argc, argv, "21", &start_val, &size_val, &flags_val);
+
+    if (NIL_P(flags_val))
+        flags_val = INT2NUM(VIR_MEMORY_VIRTUAL);
+
+    start = NUM2UINT(start_val);
+    size = NUM2UINT(size_val);
+    flags = NUM2UINT(flags_val);
+
+    buffer = ALLOC_N(char, size);
+
+    r = virDomainMemoryPeek(dom, start, size, buffer, flags);
+
+    if (r < 0) {
+        xfree(buffer);
+        rb_exc_raise(create_error(e_RetrieveError, "virDomainMemoryPeek",
+                                  conn(s)));
+    }
+
+    args.val = buffer;
+    args.size = size;
+    ret = rb_protect(rb_str_new_wrap, (VALUE)&args, &exception);
+    xfree(buffer);
+    if (exception)
+        rb_jump_tag(exception);
+
+    return ret;
+}
+#endif
+
+struct create_vcpu_array_args {
+    virVcpuInfoPtr cpuinfo;
+    unsigned char *cpumap;
+    int nr_virt_cpu;
+    int maxcpus;
+};
+
+static VALUE create_vcpu_array(VALUE input) {
+    struct create_vcpu_array_args *args;
+    VALUE result;
+    int i;
+    VALUE vcpuinfo;
+    VALUE p2vcpumap;
+    int j;
+
+    args = (struct create_vcpu_array_args *)input;
+
+    result = rb_ary_new();
+
+    for (i = 0; i < args->nr_virt_cpu; i++) {
+        vcpuinfo = rb_class_new_instance(0, NULL, c_domain_vcpuinfo);
+        rb_iv_set(vcpuinfo, "@number", UINT2NUM((args->cpuinfo)[i].number));
+        rb_iv_set(vcpuinfo, "@state", INT2NUM((args->cpuinfo)[i].state));
+        rb_iv_set(vcpuinfo, "@cpu_time", ULL2NUM((args->cpuinfo)[i].cpuTime));
+        rb_iv_set(vcpuinfo, "@cpu", INT2NUM((args->cpuinfo)[i].cpu));
+
+        p2vcpumap = rb_ary_new();
+
+        for (j = 0; j < args->maxcpus; j++)
+            rb_ary_push(p2vcpumap,
+                        (VIR_CPU_USABLE(args->cpumap,
+                                        VIR_CPU_MAPLEN(args->maxcpus), i, j)) ? Qtrue : Qfalse);
+        rb_iv_set(vcpuinfo, "@cpumap", p2vcpumap);
+
+        rb_ary_push(result, vcpuinfo);
+    }
+
+    return result;
+}
+
+/* call-seq:
+ *   dom.get_vcpus -> [ Libvirt::Domain::VCPUInfo ]
+ *
+ * Call +virDomainGetVcpus+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetVcpus]
+ * to retrieve detailed information about the state of a domain's virtual CPUs.
+ */
+static VALUE libvirt_dom_get_vcpus(VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    virNodeInfo nodeinfo;
+    virDomainInfo dominfo;
+    virVcpuInfoPtr cpuinfo;
+    unsigned char *cpumap;
+    int cpumaplen;
+    int r;
+    VALUE result;
+    int exception = 0;
+    struct create_vcpu_array_args args;
+
+    r = virNodeGetInfo(conn(s), &nodeinfo);
+    _E(r < 0, create_error(e_RetrieveError, "virNodeGetInfo", conn(s)));
+
+    r = virDomainGetInfo(dom, &dominfo);
+    _E(r < 0, create_error(e_RetrieveError, "virDomainGetInfo", conn(s)));
+
+    cpuinfo = ALLOC_N(virVcpuInfo, dominfo.nrVirtCpu);
+
+    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
+
+    /* we use malloc instead of ruby_xmalloc here to avoid a memory leak
+     * if ruby_xmalloc raises an exception
+     */
+    cpumap = malloc(dominfo.nrVirtCpu * cpumaplen);
+    if (cpumap == NULL) {
+        xfree(cpuinfo);
+        rb_memerror();
+    }
+
+    r = virDomainGetVcpus(dom, cpuinfo, dominfo.nrVirtCpu, cpumap, cpumaplen);
+    if (r < 0) {
+        xfree(cpuinfo);
+        free(cpumap);
+        rb_exc_raise(create_error(e_RetrieveError, "virDomainGetVcpus",
+                                  conn(s)));
+    }
+
+    args.cpuinfo = cpuinfo;
+    args.cpumap = cpumap;
+    args.nr_virt_cpu = dominfo.nrVirtCpu;
+    args.maxcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
+    result = rb_protect(create_vcpu_array, (VALUE)&args, &exception);
+    if (exception) {
+        xfree(cpuinfo);
+        free(cpumap);
+        rb_jump_tag(exception);
+    }
+
+    free(cpumap);
+    xfree(cpuinfo);
+
+    return result;
+}
+
+#if HAVE_VIRDOMAINISACTIVE
+/*
+ * call-seq:
+ *   dom.active? -> [true|false]
+ *
+ * Call +virDomainIsActive+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainIsActive]
+ * to determine if this domain is currently active.
+ */
+static VALUE libvirt_dom_active_p(VALUE d) {
+    gen_call_truefalse(virDomainIsActive, conn(d), domain_get(d));
+}
+#endif
+
+#if HAVE_VIRDOMAINISPERSISTENT
+/*
+ * call-seq:
+ *   dom.persistent? -> [true|false]
+ *
+ * Call +virDomainIsPersistent+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainIsPersistent]
+ * to determine if this is a persistent domain.
+ */
+static VALUE libvirt_dom_persistent_p(VALUE d) {
+    gen_call_truefalse(virDomainIsPersistent, conn(d), domain_get(d));
+}
+#endif
+
+/*
+ * call-seq:
+ *   dom.ifinfo(if) -> Libvirt::Domain::IfInfo
+ *
+ * Call +virDomainInterfaceStats+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainInterfaceStats]
+ * to retrieve statistics about domain interface if.
+ */
+static VALUE libvirt_dom_if_stats(VALUE s, VALUE sif) {
+    virDomainPtr dom = domain_get(s);
+    char *ifname = get_string_or_nil(sif);
+    virDomainInterfaceStatsStruct ifinfo;
+    int r;
+    VALUE result = Qnil;
+
+    if (ifname) {
+        r = virDomainInterfaceStats(dom, ifname, &ifinfo,
+                                    sizeof(virDomainInterfaceStatsStruct));
+        _E(r < 0, create_error(e_RetrieveError, "virDomainInterfaceStats",
+                               conn(s)));
+
+        result = rb_class_new_instance(0, NULL, c_domain_ifinfo);
+        rb_iv_set(result, "@rx_bytes", LL2NUM(ifinfo.rx_bytes));
+        rb_iv_set(result, "@rx_packets", LL2NUM(ifinfo.rx_packets));
+        rb_iv_set(result, "@rx_errs", LL2NUM(ifinfo.rx_errs));
+        rb_iv_set(result, "@rx_drop", LL2NUM(ifinfo.rx_drop));
+        rb_iv_set(result, "@tx_bytes", LL2NUM(ifinfo.tx_bytes));
+        rb_iv_set(result, "@tx_packets", LL2NUM(ifinfo.tx_packets));
+        rb_iv_set(result, "@tx_errs", LL2NUM(ifinfo.tx_errs));
+        rb_iv_set(result, "@tx_drop", LL2NUM(ifinfo.tx_drop));
+    }
+    return result;
+}
+
+/*
+ * call-seq:
+ *   dom.name -> string
+ *
+ * Call +virDomainGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetName]
+ * to retrieve the name of this domain.
+ */
+static VALUE libvirt_dom_name(VALUE s) {
+    gen_call_string(virDomainGetName, conn(s), 0, domain_get(s));
+}
+
+/*
+ * call-seq:
+ *   dom.id -> fixnum
+ *
+ * Call +virDomainGetID+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetID]
+ * to retrieve the ID of this domain.  If the domain isn't running, this will
+ * be -1.
+ */
+static VALUE libvirt_dom_id(VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    unsigned int id;
+    int out;
+
+    id = virDomainGetID(dom);
+
+    /* we need to cast the unsigned int id to a signed int out to handle the
+     * -1 case
+     */
+    out = id;
+    _E(out == -1, create_error(e_RetrieveError, "virDomainGetID", conn(s)));
+
+    return INT2NUM(out);
+}
+
+/*
+ * call-seq:
+ *   dom.uuid -> string
+ *
+ * Call +virDomainGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetUUIDString]
+ * to retrieve the UUID of this domain.
+ */
+static VALUE libvirt_dom_uuid(VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    int r;
+
+    r = virDomainGetUUIDString(dom, uuid);
+    _E(r < 0, create_error(e_RetrieveError, "virDomainGetUUIDString", conn(s)));
+
+    return rb_str_new2((char *) uuid);
+}
+
+/*
+ * call-seq:
+ *   dom.os_type -> string
+ *
+ * Call +virDomainGetOSType+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetOSType]
+ * to retrieve the os_type of this domain.  In libvirt terms, os_type determines
+ * whether this domain is fully virtualized, paravirtualized, or a container.
+ */
+static VALUE libvirt_dom_os_type(VALUE s) {
+    gen_call_string(virDomainGetOSType, conn(s), 1, domain_get(s));
+}
+
+/*
+ * call-seq:
+ *   dom.max_memory -> fixnum
+ *
+ * Call +virDomainGetMaxMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetMaxMemory]
+ * to retrieve the maximum amount of memory this domain is allowed to access.
+ * Note that the current amount of memory this domain is allowed to access may
+ * be different (see dom.memory_set).
+ */
+static VALUE libvirt_dom_max_memory(VALUE s) {
+    virDomainPtr dom = domain_get(s);
+    unsigned long max_memory;
+
+    max_memory = virDomainGetMaxMemory(dom);
+    _E(max_memory == 0, create_error(e_RetrieveError, "virDomainGetMaxMemory",
+                                     conn(s)));
+
+    return ULONG2NUM(max_memory);
+}
+
+/*
+ * call-seq:
+ *   dom.max_memory = Fixnum
+ *
+ * Call +virDomainSetMaxMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetMaxMemory]
+ * to set the maximum amount of memory (in kilobytes) this domain should be
+ * allowed to access.
+ */
+static VALUE libvirt_dom_max_memory_set(VALUE s, VALUE max_memory) {
+    virDomainPtr dom = domain_get(s);
+    int r;
+
+    r = virDomainSetMaxMemory(dom, NUM2ULONG(max_memory));
+    _E(r < 0, create_error(e_DefinitionError, "virDomainSetMaxMemory",
+                           conn(s)));
+
+    return ULONG2NUM(max_memory);
+}
+
+/*
+ * call-seq:
+ *   dom.memory = Fixnum,flags=0
+ *
+ * Call +virDomainSetMemory+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetMemory]
+ * to set the amount of memory (in kilobytes) this domain should currently
+ * have.  Note this will only succeed if both the hypervisor and the domain on
+ * this connection support ballooning.
+ */
+static VALUE libvirt_dom_memory_set(VALUE s, VALUE in) {
+    VALUE memory;
+    VALUE flags;
+    virDomainPtr dom = domain_get(s);
+    int r;
+
+    if (TYPE(in) == T_FIXNUM) {
+        memory = in;
+        flags = INT2NUM(0);
+    }
+    else if (TYPE(in) == T_ARRAY) {
+        if (RARRAY_LEN(in) != 2)
+            rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)",
+                     RARRAY_LEN(in));
+        memory = rb_ary_entry(in, 0);
+        flags = rb_ary_entry(in, 1);
+    }
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong argument type (expected Number or Array)");
+
+#if HAVE_VIRDOMAINSETMEMORYFLAGS
+    r = virDomainSetMemoryFlags(dom, NUM2ULONG(memory), NUM2UINT(flags));
+    _E(r < 0, create_error(e_DefinitionError, "virDomainSetMemoryFlags",
+                           conn(s)));
+#else
+    if (NUM2UINT(flags) != 0)
+        rb_raise(e_NoSupportError, "Non-zero flags not supported");
+    r = virDomainSetMemory(dom, NUM2ULONG(memory));
+    _E(r < 0, create_error(e_DefinitionError, "virDomainSetMemory", conn(s)));
+#endif
+
+    return ULONG2NUM(memory);
+}
+
+/*
+ * call-seq:
+ *   dom.max_vcpus -> fixnum
+ *
+ * Call +virDomainGetMaxVcpus+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetMaxVcpus]
+ * to retrieve the maximum number of virtual CPUs this domain can use.
+ */
+static VALUE libvirt_dom_max_vcpus(VALUE s) {
+    gen_call_int(virDomainGetMaxVcpus, conn(s), domain_get(s));
+}
+
+#if HAVE_VIRDOMAINGETVCPUSFLAGS
+/* call-seq:
+ *   dom.num_vcpus(flags) -> fixnum
+ *
+ * Call +virDomainGetVcpusFlags+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetVcpusFlags]
+ * to retrieve the number of virtual CPUs assigned to this domain.
+ */
+static VALUE libvirt_dom_num_vcpus(VALUE d, VALUE flags) {
+    gen_call_int(virDomainGetVcpusFlags, conn(d), domain_get(d),
+                 NUM2UINT(flags));
+}
+#endif
+
+/*
+ * call-seq:
+ *   dom.vcpus = Fixnum
+ *
+ * Call +virDomainSetVcpus+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetVcpus]
+ * to set the current number of virtual CPUs this domain should have.  Note
+ * that this will only work if both the hypervisor and domain on this
+ * connection support virtual CPU hotplug/hot-unplug.
+ */
+static VALUE libvirt_dom_vcpus_set(VALUE s, VALUE nvcpus) {
+    gen_call_void(virDomainSetVcpus, conn(s), domain_get(s), NUM2UINT(nvcpus));
+}
+
+#if HAVE_VIRDOMAINSETVCPUSFLAGS
+/*
+ * call-seq:
+ *   dom.vcpus_flags = Fixnum,flags
+ *
+ * Call +virDomainSetVcpusFlags+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetVcpusFlags]
+ * to set the current number of virtual CPUs this domain should have.  The
+ * flags parameter controls whether the change is made to the running domain
+ * the domain configuration, or both, and must not be 0.
+ */
+static VALUE libvirt_dom_vcpus_set_flags(VALUE s, VALUE vcpus) {
+    VALUE nvcpus;
+    VALUE flags;
+
+    Check_Type(vcpus, T_ARRAY);
+
+    if (RARRAY_LEN(vcpus) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(vcpus));
+
+    nvcpus = rb_ary_entry(vcpus, 0);
+    flags = rb_ary_entry(vcpus, 1);
+
+    gen_call_void(virDomainSetVcpusFlags, conn(s), domain_get(s),
+                  NUM2UINT(nvcpus), NUM2UINT(flags));
+}
+#endif
+
+/*
+ * call-seq:
+ *   dom.pin_vcpu(vcpu, cpulist) -> nil
+ *
+ * Call +virDomainPinVcpu+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainPinVcpu]
+ * to pin a particular virtual CPU to a range of physical processors.  The
+ * cpulist should be an array of Fixnums representing the physical processors
+ * this virtual CPU should be allowed to be scheduled on.
+ */
+static VALUE libvirt_dom_pin_vcpu(VALUE s, VALUE vcpu, VALUE cpulist) {
+    virDomainPtr dom = domain_get(s);
+    int r, i, len, maplen;
+    unsigned char *cpumap;
+    virNodeInfo nodeinfo;
+    virConnectPtr c = conn(s);
+    unsigned int vcpunum;
+
+    vcpunum = NUM2UINT(vcpu);
+    Check_Type(cpulist, T_ARRAY);
+
+    r = virNodeGetInfo(c, &nodeinfo);
+    _E(r < 0, create_error(e_RetrieveError, "virNodeGetInfo", c));
+
+    maplen = VIR_CPU_MAPLEN(nodeinfo.cpus);
+    cpumap = ALLOC_N(unsigned char, maplen);
+    MEMZERO(cpumap, unsigned char, maplen);
+
+    len = RARRAY_LEN(cpulist);
+    for(i = 0; i < len; i++) {
+        VALUE e = rb_ary_entry(cpulist, i);
+        VIR_USE_CPU(cpumap, NUM2UINT(e));
+    }
+
+    r = virDomainPinVcpu(dom, vcpunum, cpumap, maplen);
+    xfree(cpumap);
+    _E(r < 0, create_error(e_RetrieveError, "virDomainPinVcpu", c));
+
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *   dom.xml_desc(flags=0) -> string
+ *
+ * Call +virDomainGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetXMLDesc]
+ * to retrieve the XML describing this domain.
+ */
+static VALUE libvirt_dom_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virDomainGetXMLDesc, conn(s), 1, domain_get(s),
+                    NUM2INT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.undefine -> nil
+ *
+ * Call +virDomainUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainUndefine]
+ * to undefine the domain.  After this call, the domain object is no longer
+ * valid.
+ */
+static VALUE libvirt_dom_undefine(VALUE s) {
+    gen_call_void(virDomainUndefine, conn(s), domain_get(s));
+}
+
+/*
+ * call-seq:
+ *   dom.create(flags=0) -> nil
+ *
+ * Call +virDomainCreate+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCreate]
+ * to start an already defined domain.
+ */
+static VALUE libvirt_dom_create(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+#if HAVE_VIRDOMAINCREATEWITHFLAGS
+    gen_call_void(virDomainCreateWithFlags, conn(s), domain_get(s),
+                  NUM2UINT(flags));
+#else
+    if (NUM2UINT(flags) != 0)
+        rb_raise(e_NoSupportError, "Non-zero flags not supported");
+    gen_call_void(virDomainCreate, conn(s), domain_get(s));
+#endif
+}
+
+/*
+ * call-seq:
+ *   dom.autostart -> [true|false]
+ *
+ * Call +virDomainGetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetAutostart]
+ * to find out the state of the autostart flag for a domain.
+ */
+static VALUE libvirt_dom_autostart(VALUE s){
+    virDomainPtr dom = domain_get(s);
+    int r, autostart;
+
+    r = virDomainGetAutostart(dom, &autostart);
+    _E(r < 0, create_error(e_RetrieveError, "virDomainAutostart", conn(s)));
+
+    return autostart ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   dom.autostart = [true|false]
+ *
+ * Call +virDomainSetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetAutostart]
+ * to make this domain autostart when libvirtd starts up.
+ */
+static VALUE libvirt_dom_autostart_set(VALUE s, VALUE autostart) {
+    if (autostart != Qtrue && autostart != Qfalse)
+		rb_raise(rb_eTypeError,
+                 "wrong argument type (expected TrueClass or FalseClass)");
+
+    gen_call_void(virDomainSetAutostart, conn(s),
+                  domain_get(s), RTEST(autostart) ? 1 : 0);
+}
+
+/*
+ * call-seq:
+ *   dom.attach_device(device_xml, flags=0) -> nil
+ *
+ * Call +virDomainAttachDevice+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainAttachDevice]
+ * to attach the device described by the device_xml to the domain.
+ */
+static VALUE libvirt_dom_attach_device(int argc, VALUE *argv, VALUE s) {
+    VALUE xml;
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+#if HAVE_VIRDOMAINATTACHDEVICEFLAGS
+    gen_call_void(virDomainAttachDeviceFlags, conn(s), domain_get(s),
+                  StringValueCStr(xml), NUM2UINT(flags));
+#else
+    if (NUM2UINT(flags) != 0)
+        rb_raise(e_NoSupportError, "Non-zero flags not supported");
+    gen_call_void(virDomainAttachDevice, conn(s), domain_get(s),
+                  StringValueCStr(xml));
+#endif
+}
+
+/*
+ * call-seq:
+ *   dom.detach_device(device_xml, flags=0) -> nil
+ *
+ * Call +virDomainDetachDevice+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainDetachDevice]
+ * to detach the device described by the device_xml from the domain.
+ */
+static VALUE libvirt_dom_detach_device(int argc, VALUE *argv, VALUE s) {
+    VALUE xml;
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+#if HAVE_VIRDOMAINDETACHDEVICEFLAGS
+    gen_call_void(virDomainDetachDeviceFlags, conn(s), domain_get(s),
+                  StringValueCStr(xml), NUM2UINT(flags));
+#else
+    if (NUM2UINT(flags) != 0)
+        rb_raise(e_NoSupportError, "Non-zero flags not supported");
+    gen_call_void(virDomainDetachDevice, conn(s), domain_get(s),
+                  StringValueCStr(xml));
+#endif
+}
+
+#if HAVE_VIRDOMAINUPDATEDEVICEFLAGS
+/*
+ * call-seq:
+ *   dom.update_device(device_xml, flags=0) -> nil
+ *
+ * Call +virDomainUpdateDeviceFlags+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainUpdateDeviceFlags]
+ * to update the device described by the device_xml.
+ */
+static VALUE libvirt_dom_update_device(int argc, VALUE *argv, VALUE s) {
+    VALUE xml;
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainUpdateDeviceFlags, conn(s), domain_get(s),
+                  StringValueCStr(xml), NUM2UINT(flags));
+}
+#endif
+
+/*
+ * call-seq:
+ *   dom.free -> nil
+ *
+ * Call +virDomainFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainFree]
+ * to free a domain object.
+ */
+static VALUE libvirt_dom_free(VALUE s) {
+    gen_call_free(Domain, s);
+}
+
+#if HAVE_TYPE_VIRDOMAINSNAPSHOTPTR
+static void domain_snapshot_free(void *d) {
+    generic_free(DomainSnapshot, d);
+}
+
+static VALUE domain_snapshot_new(virDomainSnapshotPtr d, VALUE domain) {
+    VALUE result;
+    result = Data_Wrap_Struct(c_domain_snapshot, NULL, domain_snapshot_free, d);
+    rb_iv_set(result, "@domain", domain);
+    return result;
+}
+
+static virDomainSnapshotPtr domain_snapshot_get(VALUE s) {
+    generic_get(DomainSnapshot, s);
+}
+
+/*
+ * call-seq:
+ *   dom.snapshot_create_xml(snapshot_xml, flags=0) -> Libvirt::Domain::Snapshot
+ *
+ * Call +virDomainSnapshotCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotCreateXML]
+ * to create a new snapshot based on snapshot_xml.
+ */
+static VALUE libvirt_dom_snapshot_create_xml(int argc, VALUE *argv, VALUE d) {
+    VALUE xmlDesc, flags;
+    virDomainSnapshotPtr ret;
+
+    rb_scan_args(argc, argv, "11", &xmlDesc, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    ret = virDomainSnapshotCreateXML(domain_get(d), StringValueCStr(xmlDesc),
+                                     NUM2UINT(flags));
+
+    _E(ret == NULL, create_error(e_Error, "virDomainSnapshotCreateXML",
+                                 conn(d)));
+
+    return domain_snapshot_new(ret, d);
+}
+
+/*
+ * call-seq:
+ *   dom.num_of_snapshots(flags=0) -> fixnum
+ *
+ * Call +virDomainSnapshotNum+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotNum]
+ * to retrieve the number of available snapshots for this domain.
+ */
+static VALUE libvirt_dom_num_of_snapshots(int argc, VALUE *argv, VALUE d) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_int(virDomainSnapshotNum, conn(d), domain_get(d),
+                 NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.list_snapshots(flags=0) -> list
+ *
+ * Call +virDomainSnapshotListNames+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotListNames]
+ * to retrieve a list of snapshot names available for this domain.
+ */
+static VALUE libvirt_dom_list_snapshots(int argc, VALUE *argv, VALUE d) {
+    VALUE flags_val;
+    int r;
+    int num;
+    virDomainPtr dom = domain_get(d);
+    char **names;
+    unsigned int flags;
+
+    rb_scan_args(argc, argv, "01", &flags_val);
+
+    if (NIL_P(flags_val))
+        flags = 0;
+    else
+        flags = NUM2UINT(flags_val);
+
+    num = virDomainSnapshotNum(dom, 0);
+    _E(num < 0, create_error(e_RetrieveError, "virDomainSnapshotNum", conn(d)));
+    if (num == 0)
+        /* if num is 0, don't call virDomainSnapshotListNames function */
+        return rb_ary_new2(num);
+
+    names = ALLOC_N(char *, num);
+
+    r = virDomainSnapshotListNames(domain_get(d), names, num, flags);
+    if (r < 0) {
+        xfree(names);
+        rb_exc_raise(create_error(e_RetrieveError, "virDomainSnapshotListNames",
+                                  conn(d)));
+    }
+
+    return gen_list(num, &names);
+}
+
+/*
+ * call-seq:
+ *   dom.lookup_snapshot_by_name(name, flags=0) -> Libvirt::Domain::Snapshot
+ *
+ * Call +virDomainSnapshotLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotLookupByName]
+ * to retrieve a snapshot object corresponding to snapshot name.
+ */
+static VALUE libvirt_dom_lookup_snapshot_by_name(int argc, VALUE *argv, VALUE d) {
+    virDomainPtr dom = domain_get(d);
+    virDomainSnapshotPtr snap;
+    VALUE name, flags;
+
+    rb_scan_args(argc, argv, "11", &name, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    snap = virDomainSnapshotLookupByName(dom, StringValueCStr(name),
+                                         NUM2UINT(flags));
+    _E(dom == NULL, create_error(e_RetrieveError,
+                                 "virDomainSnapshotLookupByName", conn(d)));
+
+    return domain_snapshot_new(snap, d);
+}
+
+/*
+ * call-seq:
+ *   dom.has_current_snapshot?(flags=0) -> [true|false]
+ *
+ * Call +virDomainHasCurrentSnapshot+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainHasCurrentSnapshot]
+ * to find out if this domain has a snapshot active.
+ */
+static VALUE libvirt_dom_has_current_snapshot_p(int argc, VALUE *argv, VALUE d) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_truefalse(virDomainHasCurrentSnapshot, conn(d), domain_get(d),
+                       NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.revert_to_snapshot(snapshot_object, flags=0) -> nil
+ *
+ * Call +virDomainRevertToSnapshot+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainRevertToSnapshot]
+ * to restore this domain to a previously saved snapshot.
+ */
+static VALUE libvirt_dom_revert_to_snapshot(int argc, VALUE *argv, VALUE d) {
+    VALUE snap, flags;
+
+    rb_scan_args(argc, argv, "11", &snap, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainRevertToSnapshot, conn(d),
+                  domain_snapshot_get(snap), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   dom.current_snapshot(flags=0) -> Libvirt::Domain::Snapshot
+ *
+ * Call +virDomainCurrentSnapshot+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainCurrentSnapshot]
+ * to retrieve the current snapshot for this domain (if any).
+ */
+static VALUE libvirt_dom_current_snapshot(int argc, VALUE *argv, VALUE d) {
+    VALUE flags;
+    virDomainSnapshotPtr snap;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    snap = virDomainSnapshotCurrent(domain_get(d), NUM2UINT(flags));
+    _E(snap == NULL, create_error(e_RetrieveError, "virDomainSnapshotCurrent",
+                                  conn(d)));
+
+    return domain_snapshot_new(snap, d);
+}
+
+/*
+ * call-seq:
+ *   snapshot.xml_desc(flags=0) -> string
+ *
+ * Call +virDomainSnapshotGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotGetXMLDesc]
+ * to retrieve the xml description for this snapshot.
+ */
+static VALUE libvirt_dom_snapshot_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virDomainSnapshotGetXMLDesc, conn(s), 1,
+                    domain_snapshot_get(s), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   snapshot.delete(flags=0) -> nil
+ *
+ * Call +virDomainSnapshotDelete+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotDelete]
+ * to delete this snapshot.
+ */
+static VALUE libvirt_dom_snapshot_delete(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainSnapshotDelete, conn(s),
+                  domain_snapshot_get(s), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   snapshot.free -> nil
+ *
+ * Call +virDomainSnapshotFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotFree]
+ * to free up the snapshot object.  After this call the snapshot object is
+ * no longer valid.
+ */
+static VALUE libvirt_dom_snapshot_free(VALUE s) {
+    gen_call_free(DomainSnapshot, s);
+}
+
+#endif
+
+#if HAVE_TYPE_VIRDOMAINJOBINFOPTR
+/*
+ * call-seq:
+ *   dom.job_info -> Libvirt::Domain::JobInfo
+ *
+ * Call +virDomainGetJobInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetJobInfo]
+ * to retrieve the current state of the running domain job.
+ */
+static VALUE libvirt_dom_job_info(VALUE d) {
+    int r;
+    virDomainJobInfo info;
+    VALUE result;
+
+    r = virDomainGetJobInfo(domain_get(d), &info);
+    _E(r < 0, create_error(e_RetrieveError, "virDomainGetJobInfo", conn(d)));
+
+    result = rb_class_new_instance(0, NULL, c_domain_job_info);
+    rb_iv_set(result, "@type", INT2NUM(info.type));
+    rb_iv_set(result, "@time_elapsed", ULL2NUM(info.timeElapsed));
+    rb_iv_set(result, "@time_remaining", ULL2NUM(info.timeRemaining));
+    rb_iv_set(result, "@data_total", ULL2NUM(info.dataTotal));
+    rb_iv_set(result, "@data_processed", ULL2NUM(info.dataProcessed));
+    rb_iv_set(result, "@data_remaining", ULL2NUM(info.dataRemaining));
+    rb_iv_set(result, "@mem_total", ULL2NUM(info.memTotal));
+    rb_iv_set(result, "@mem_processed", ULL2NUM(info.memProcessed));
+    rb_iv_set(result, "@mem_remaining", ULL2NUM(info.memRemaining));
+    rb_iv_set(result, "@file_total", ULL2NUM(info.fileTotal));
+    rb_iv_set(result, "@file_processed", ULL2NUM(info.fileProcessed));
+    rb_iv_set(result, "@file_remaining", ULL2NUM(info.fileRemaining));
+
+    return result;
+}
+
+/*
+ * call-seq:
+ *   dom.abort_job -> nil
+ *
+ * Call +virDomainAbortJob+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainAbortJob]
+ * to abort the currently running job on this domain.
+ */
+static VALUE libvirt_dom_abort_job(VALUE d) {
+    gen_call_void(virDomainAbortJob, conn(d), domain_get(d));
+}
+
+#endif
+
+struct create_sched_type_args {
+    char *type;
+    int nparams;
+};
+
+static VALUE create_sched_type_array(VALUE input) {
+    struct create_sched_type_args *args;
+    VALUE result;
+
+    args = (struct create_sched_type_args *)input;
+
+    result = rb_ary_new();
+    rb_ary_push(result, rb_str_new2(args->type));
+    rb_ary_push(result, INT2NUM(args->nparams));
+
+    return result;
+}
+
+/*
+ * call-seq:
+ *   dom.scheduler_type -> [type, #params]
+ *
+ * Call +virDomainGetSchedulerType+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetSchedulerType]
+ * to retrieve the scheduler type used on this domain.
+ */
+static VALUE libvirt_dom_scheduler_type(VALUE d) {
+    int nparams;
+    char *type;
+    VALUE result;
+    int exception = 0;
+    struct create_sched_type_args args;
+
+    type = virDomainGetSchedulerType(domain_get(d), &nparams);
+
+    _E(type == NULL, create_error(e_RetrieveError, "virDomainGetSchedulerType",
+                                  conn(d)));
+
+    args.type = type;
+    args.nparams = nparams;
+    result = rb_protect(create_sched_type_array, (VALUE)&args, &exception);
+    if (exception) {
+        free(type);
+        rb_jump_tag(exception);
+    }
+
+    return result;
+}
+
+#if HAVE_VIRDOMAINQEMUMONITORCOMMAND
+/*
+ * call-seq:
+ *   dom.qemu_monitor_command(cmd, flags=0) -> string
+ *
+ * Call virDomainQemuMonitorCommand
+ * to send a qemu command directly to the monitor.  Note that this will only
+ * work on qemu hypervisors, and the input and output formats are not
+ * guaranteed to be stable.  Also note that using this command can severly
+ * impede libvirt's ability to manage the domain; use with caution!
+ */
+static VALUE libvirt_dom_qemu_monitor_command(int argc, VALUE *argv, VALUE d) {
+    VALUE cmd, flags;
+    char *result;
+    VALUE ret;
+    int exception;
+    virConnectPtr c;
+    const char *type;
+    int r;
+
+    rb_scan_args(argc, argv, "11", &cmd, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    c = conn(d);
+    type = virConnectGetType(c);
+    _E(type == NULL, create_error(e_Error, "virConnectGetType", c));
+    if (strcmp(type, "QEMU") != 0)
+        rb_raise(rb_eTypeError,
+                 "Tried to use virDomainQemuMonitor command on %s connection",
+                 type);
+
+    r = virDomainQemuMonitorCommand(domain_get(d), StringValueCStr(cmd),
+                                    &result, NUM2UINT(flags));
+    _E(r < 0, create_error(e_RetrieveError, "virDomainQemuMonitorCommand", c));
+
+    ret = rb_protect(rb_str_new2_wrap, (VALUE)&result, &exception);
+    free(result);
+    if (exception)
+        rb_jump_tag(exception);
+
+    return ret;
+}
+#endif
+
+#if HAVE_VIRDOMAINISUPDATED
+/*
+ * call-seq:
+ *   dom.updated? ->  [True|False]
+ * Call +virDomainIsUpdated+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainIsUpdated]
+ * to determine whether the definition for this domain has been updated.
+ */
+static VALUE libvirt_dom_is_updated(VALUE d) {
+    gen_call_truefalse(virDomainIsUpdated, conn(d), domain_get(d));
+}
+#endif
+
+struct field_to_value {
+    VALUE result;
+    virTypedParameterPtr param;
+};
+
+static VALUE typed_field_to_value(VALUE input) {
+    struct field_to_value *ftv = (struct field_to_value *)input;
+    VALUE val;
+
+    switch(ftv->param->type) {
+    case VIR_TYPED_PARAM_INT:
+        val = INT2NUM(ftv->param->value.i);
+        break;
+    case VIR_TYPED_PARAM_UINT:
+        val = UINT2NUM(ftv->param->value.ui);
+        break;
+    case VIR_TYPED_PARAM_LLONG:
+        val = LL2NUM(ftv->param->value.l);
+        break;
+    case VIR_TYPED_PARAM_ULLONG:
+        val = ULL2NUM(ftv->param->value.ul);
+        break;
+    case VIR_TYPED_PARAM_DOUBLE:
+        val = rb_float_new(ftv->param->value.d);
+        break;
+    case VIR_TYPED_PARAM_BOOLEAN:
+        val = (ftv->param->value.b == 0) ? Qfalse : Qtrue;
+        break;
+    default:
+        rb_raise(rb_eArgError, "Invalid parameter type");
+    }
+
+    rb_hash_aset(ftv->result, rb_str_new2(ftv->param->field), val);
+
+    return Qnil;
+}
+
+static VALUE internal_get_parameters(int argc, VALUE *argv, VALUE d,
+                                     int (*nparams_cb)(VALUE d,
+                                                       unsigned int flags),
+                                     char *(*get_cb)(VALUE d,
+                                                     unsigned int flags,
+                                                     virTypedParameterPtr params,
+                                                     int *nparams)) {
+    int nparams;
+    virTypedParameterPtr params;
+    VALUE result;
+    int i;
+    int exception;
+    char *errname;
+    struct field_to_value ftv;
+    unsigned int flags;
+    VALUE flags_val;
+
+    rb_scan_args(argc, argv, "01", &flags_val);
+
+    if (NIL_P(flags_val))
+        flags = 0;
+    else
+        flags = NUM2UINT(flags_val);
+
+    nparams = nparams_cb(d, flags);
+
+    result = rb_hash_new();
+
+    if (nparams == 0)
+        return result;
+
+    params = ALLOC_N(virTypedParameter, nparams);
+
+    errname = get_cb(d, flags, params, &nparams);
+    if (errname != NULL) {
+        xfree(params);
+        rb_exc_raise(create_error(e_RetrieveError, errname, conn(d)));
+    }
+
+    for (i = 0; i < nparams; i++) {
+        ftv.result = result;
+        ftv.param = &params[i];
+        rb_protect(typed_field_to_value, (VALUE)&ftv, &exception);
+        if (exception) {
+            xfree(params);
+            rb_jump_tag(exception);
+        }
+    }
+
+    xfree(params);
+
+    return result;
+}
+
+struct value_to_field {
+    virTypedParameterPtr param;
+    VALUE input;
+};
+
+static VALUE typed_value_to_field(VALUE in) {
+    struct value_to_field *vtf = (struct value_to_field *)in;
+    VALUE val;
+
+    val = rb_hash_aref(vtf->input, rb_str_new2(vtf->param->field));
+    if (NIL_P(val))
+        return Qnil;
+
+    switch(vtf->param->type) {
+    case VIR_TYPED_PARAM_INT:
+        vtf->param->value.i = NUM2INT(val);
+        break;
+    case VIR_TYPED_PARAM_UINT:
+        vtf->param->value.ui = NUM2UINT(val);
+        break;
+    case VIR_TYPED_PARAM_LLONG:
+        vtf->param->value.l = NUM2LL(val);
+        break;
+    case VIR_TYPED_PARAM_ULLONG:
+        vtf->param->value.ul = NUM2ULL(val);
+        break;
+    case VIR_TYPED_PARAM_DOUBLE:
+        vtf->param->value.d = NUM2DBL(val);
+        break;
+    case VIR_TYPED_PARAM_BOOLEAN:
+        vtf->param->value.b = (val == Qtrue) ? 1 : 0;
+        break;
+    default:
+        rb_raise(rb_eArgError, "Invalid parameter type");
+    }
+
+    return Qnil;
+}
+
+static VALUE internal_set_parameters(VALUE d, VALUE in,
+                                     int (*nparams_cb)(VALUE d,
+                                                       unsigned int flags),
+                                     char *(*get_cb)(VALUE d,
+                                                     unsigned int flags,
+                                                     virTypedParameterPtr params,
+                                                     int *nparams),
+                                     char *(*set_cb)(VALUE d,
+                                                     unsigned int flags,
+                                                     virTypedParameterPtr params,
+                                                     int nparams)) {
+    int nparams;
+    virTypedParameterPtr params;
+    int exception;
+    int i;
+    char *errname;
+    struct value_to_field vtf;
+    VALUE input;
+    VALUE flags_val;
+    unsigned int flags;
+
+    if (TYPE(in) == T_HASH) {
+        input = in;
+        flags_val = INT2NUM(0);
+    }
+    else if (TYPE(in) == T_ARRAY) {
+        if (RARRAY_LEN(in) != 2)
+            rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)",
+                     RARRAY_LEN(in));
+        input = rb_ary_entry(in, 0);
+        flags_val = rb_ary_entry(in, 1);
+    }
+    else
+        rb_raise(rb_eTypeError, "wrong argument type (expected Hash or Array)");
+
+    Check_Type(input, T_HASH);
+
+    /* we do this up-front for proper argument error checking */
+    flags = NUM2UINT(flags_val);
+
+    if (RHASH_SIZE(input) == 0)
+        return Qnil;
+
+    /* Complicated.  The below all stems from the fact that we have no way to
+     * have no way to discover what type each parameter should be based on the
+     * be based on the input.  Instead, we ask libvirt to give us the current
+     * us the current parameters and types, and then we replace the values with
+     * the values with the new values.  That way we find out what the old types
+     * what the old types were, and if the new types don't match, libvirt will
+     * throw an error.
+     */
+
+    nparams = nparams_cb(d, flags);
+
+    params = ALLOC_N(virTypedParameter, nparams);
+
+    errname = get_cb(d, flags, params, &nparams);
+    if (errname != NULL) {
+        xfree(params);
+        rb_exc_raise(create_error(e_RetrieveError, errname, conn(d)));
+    }
+
+    for (i = 0; i < nparams; i++) {
+        vtf.param = &params[i];
+        vtf.input = input;
+        rb_protect(typed_value_to_field, (VALUE)&vtf, &exception);
+        if (exception) {
+            xfree(params);
+            rb_jump_tag(exception);
+        }
+    }
+
+    errname = set_cb(d, flags, params, nparams);
+    if (errname != NULL) {
+        xfree(params);
+        rb_exc_raise(create_error(e_RetrieveError, errname, conn(d)));
+    }
+
+    xfree(params);
+
+    return Qnil;
+}
+
+static int scheduler_nparams(VALUE d, unsigned int flags) {
+    int nparams;
+    char *type;
+
+    type = virDomainGetSchedulerType(domain_get(d), &nparams);
+    _E(type == NULL, create_error(e_RetrieveError, "virDomainGetSchedulerType",
+                                  conn(d)));
+    xfree(type);
+
+    return nparams;
+}
+
+static char *scheduler_get(VALUE d, unsigned int flags,
+                           virTypedParameterPtr params, int *nparams) {
+#ifdef HAVE_TYPE_VIRTYPEDPARAMETERPTR
+    if (virDomainGetSchedulerParametersFlags(domain_get(d), params, nparams,
+                                             flags) < 0)
+        return "virDomainGetSchedulerParameters";
+#else
+    if (flags != 0)
+        rb_raise(e_NoSupportError, "Non-zero flags not supported");
+    if (virDomainGetSchedulerParameters(domain_get(d),
+                                        (virSchedParameterPtr)params,
+                                        nparams) < 0)
+        return "virDomainGetSchedulerParameters";
+#endif
+
+    return NULL;
+}
+
+static char *scheduler_set(VALUE d, unsigned int flags,
+                           virTypedParameterPtr params, int nparams) {
+#if HAVE_TYPE_VIRTYPEDPARAMETERPTR
+    if (virDomainSetSchedulerParametersFlags(domain_get(d), params, nparams,
+                                             flags) < 0)
+        return "virDomainSetSchedulerParameters";
+#else
+    if (flags != 0)
+        rb_raise(e_NoSupportError, "Non-zero flags not supported");
+    if (virDomainSetSchedulerParameters(domain_get(d),
+                                        (virSchedParameterPtr)params,
+                                        nparams) < 0)
+        return "virDomainSetSchedulerParameters";
+#endif
+
+    return NULL;
+}
+
+/*
+ * call-seq:
+ *   dom.scheduler_parameters(flags=0) -> Hash
+ *
+ * Call +virDomainGetSchedulerParameters+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetSchedulerParameters]
+ * to retrieve all of the scheduler parameters for this domain.  The keys and
+ * values in the hash that is returned are hypervisor specific.
+ */
+static VALUE libvirt_dom_get_scheduler_parameters(int argc, VALUE *argv,
+                                                  VALUE d) {
+    return internal_get_parameters(argc, argv, d, scheduler_nparams,
+                                   scheduler_get);
+}
+
+/*
+ * call-seq:
+ *   dom.scheduler_parameters = Hash,flags=0
+ *
+ * Call +virDomainSetSchedulerParameters+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetSchedulerParameters]
+ * to set the scheduler parameters for this domain.  The keys and values in
+ * the input hash are hypervisor specific.  If an empty hash is given, no
+ * changes are made (and no error is raised).
+ */
+static VALUE libvirt_dom_set_scheduler_parameters(VALUE d, VALUE input) {
+    return internal_set_parameters(d, input, scheduler_nparams, scheduler_get,
+                                   scheduler_set);
+}
+
+#if HAVE_VIRDOMAINSETMEMORYPARAMETERS
+static int memory_nparams(VALUE d, unsigned int flags) {
+    int nparams = 0;
+    int ret;
+
+    ret = virDomainGetMemoryParameters(domain_get(d), NULL, &nparams, flags);
+    _E(ret < 0, create_error(e_RetrieveError, "virDomainGetMemoryParameters",
+                             conn(d)));
+
+    return nparams;
+}
+
+static char *memory_get(VALUE d, unsigned int flags,
+                        virTypedParameterPtr params, int *nparams) {
+#ifdef HAVE_TYPE_VIRTYPEDPARAMETERPTR
+    if (virDomainGetMemoryParameters(domain_get(d), params, nparams, flags) < 0)
+#else
+    if (virDomainGetMemoryParameters(domain_get(d),
+                                     (virMemoryParameterPtr)params, nparams,
+                                     flags) < 0)
+#endif
+        return "virDomainGetMemoryParameters";
+
+    return NULL;
+}
+
+static char *memory_set(VALUE d, unsigned int flags,
+                        virTypedParameterPtr params, int nparams) {
+#ifdef HAVE_TYPE_VIRTYPEDPARAMETERPTR
+    if (virDomainSetMemoryParameters(domain_get(d), params, nparams, flags) < 0)
+#else
+    if (virDomainSetMemoryParameters(domain_get(d),
+                                     (virMemoryParameterPtr)params, nparams,
+                                     flags) < 0)
+#endif
+        return "virDomainSetMemoryParameters";
+
+    return NULL;
+}
+
+/*
+ * call-seq:
+ *   dom.memory_parameters(flags=0) -> Hash
+ *
+ * Call +virDomainGetMemoryParameters+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetMemoryParameters]
+ * to retrieve all of the memory parameters for this domain.  The keys and
+ * values in the hash that is returned are hypervisor specific.
+ */
+static VALUE libvirt_dom_get_memory_parameters(int argc, VALUE *argv, VALUE d) {
+    return internal_get_parameters(argc, argv, d, memory_nparams, memory_get);
+}
+
+/*
+ * call-seq:
+ *   dom.memory_parameters = Hash,flags=0
+ *
+ * Call +virDomainSetMemoryParameters+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetMemoryParameters]
+ * to set the memory parameters for this domain.  The keys and values in
+ * the input hash are hypervisor specific.
+ */
+static VALUE libvirt_dom_set_memory_parameters(VALUE d, VALUE in) {
+    return internal_set_parameters(d, in, memory_nparams, memory_get,
+                                   memory_set);
+}
+#endif
+
+#if HAVE_VIRDOMAINSETBLKIOPARAMETERS
+static int blkio_nparams(VALUE d, unsigned int flags) {
+    int nparams = 0;
+    int ret;
+
+    ret = virDomainGetBlkioParameters(domain_get(d), NULL, &nparams, flags);
+    _E(ret < 0, create_error(e_RetrieveError, "virDomainGetBlkioParameters",
+                             conn(d)));
+
+    return nparams;
+}
+
+static char *blkio_get(VALUE d, unsigned int flags, virTypedParameterPtr params,
+                       int *nparams) {
+#ifdef HAVE_TYPE_VIRTYPEDPARAMETERPTR
+    if (virDomainGetBlkioParameters(domain_get(d), params, nparams, flags) < 0)
+#else
+    if (virDomainGetBlkioParameters(domain_get(d),
+                                    (virBlkioParameterPtr)params, nparams,
+                                    flags) < 0)
+#endif
+        return "virDomainGetBlkioParameters";
+
+    return NULL;
+}
+
+static char *blkio_set(VALUE d, unsigned int flags, virTypedParameterPtr params,
+                       int nparams) {
+#ifdef HAVE_TYPE_VIRTYPEDPARAMETERPTR
+    if (virDomainSetBlkioParameters(domain_get(d), params, nparams, flags) < 0)
+#else
+    if (virDomainSetBlkioParameters(domain_get(d),
+                                    (virBlkioParameterPtr)params, nparams,
+                                    flags) < 0)
+#endif
+        return "virDomainSetBlkioParameters";
+
+    return NULL;
+}
+
+/*
+ * call-seq:
+ *   dom.blkio_parameters(flags=0) -> Hash
+ *
+ * Call +virDomainGetBlkioParameters+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetBlkioParameters]
+ * to retrieve all of the blkio parameters for this domain.  The keys and
+ * values in the hash that is returned are hypervisor specific.
+ */
+static VALUE libvirt_dom_get_blkio_parameters(int argc, VALUE *argv, VALUE d) {
+    return internal_get_parameters(argc, argv, d, blkio_nparams, blkio_get);
+}
+
+/*
+ * call-seq:
+ *   dom.memory_parameters = Hash,flags=0
+ *
+ * Call +virDomainSetBlkioParameters+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSetBlkioParameters]
+ * to set the blkio parameters for this domain.  The keys and values in
+ * the input hash are hypervisor specific.
+ */
+static VALUE libvirt_dom_set_blkio_parameters(VALUE d, VALUE in) {
+    return internal_set_parameters(d, in, blkio_nparams, blkio_get, blkio_set);
+}
+#endif
+
+#if HAVE_VIRDOMAINGETSTATE
+/*
+ * call-seq:
+ *   dom.state(flags=0) -> state, reason
+ *
+ * Call +virDomainGetState+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainGetState]
+ * to get the current state of the domain.
+ */
+static VALUE libvirt_dom_get_state(int argc, VALUE *argv, VALUE d) {
+    VALUE flags;
+    int state, reason;
+    VALUE result;
+    int retval;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    retval = virDomainGetState(domain_get(d), &state, &reason, NUM2INT(flags));
+    _E(retval < 0, create_error(e_Error, "virDomainGetState", conn(d)));
+
+    result = rb_ary_new();
+
+    rb_ary_push(result, INT2NUM(state));
+    rb_ary_push(result, INT2NUM(reason));
+
+    return result;
+}
+#endif
+
+#if HAVE_VIRDOMAINOPENCONSOLE
+/*
+ * call-seq:
+ *   dom.open_console(device, stream, flags=0) -> nil
+ *
+ * Call +virDomainOpenConsole+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainOpenConsole]
+ * to open up a console to device over stream.
+ */
+static VALUE libvirt_dom_open_console(int argc, VALUE *argv, VALUE d) {
+    VALUE dev, st, flags;
+
+    rb_scan_args(argc, argv, "21", &dev, &st, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainOpenConsole, conn(d), domain_get(d),
+                  StringValueCStr(dev), stream_get(st), NUM2INT(flags));
+}
+#endif
+
+#if HAVE_VIRDOMAINSCREENSHOT
+/*
+ * call-seq:
+ *   dom.screenshot(stream, screen, flags=0) -> nil
+ *
+ * Call +virDomainScreenshot+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainScreenshot]
+ * to take a screenshot of the domain console as a stream.
+ */
+static VALUE libvirt_dom_screenshot(int argc, VALUE *argv, VALUE d) {
+    VALUE st, screen, flags;
+
+    rb_scan_args(argc, argv, "21", &st, &screen, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virDomainScreenshot, conn(d), 1, domain_get(d),
+                    stream_get(st), NUM2UINT(screen), NUM2UINT(flags));
+}
+#endif
+
+#if HAVE_VIRDOMAININJECTNMI
+/*
+ * call-seq:
+ *   dom.inject_nmi(flags=0) -> nil
+ *
+ * Call +virDomainInjectNMI+[http://www.libvirt.org/html/libvirt-libvirt.html#virDomainInjectNMI]
+ * to send an NMI to the guest.
+ */
+static VALUE libvirt_dom_inject_nmi(int argc, VALUE *argv, VALUE d) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virDomainInjectNMI, conn(d), domain_get(d), NUM2UINT(flags));
+}
+#endif
+
+/*
+ * Class Libvirt::Domain
+ */
+void init_domain()
+{
+    c_domain = rb_define_class_under(m_libvirt, "Domain", rb_cObject);
+
+    rb_define_const(c_domain, "NOSTATE", INT2NUM(VIR_DOMAIN_NOSTATE));
+    rb_define_const(c_domain, "RUNNING", INT2NUM(VIR_DOMAIN_RUNNING));
+    rb_define_const(c_domain, "BLOCKED", INT2NUM(VIR_DOMAIN_BLOCKED));
+    rb_define_const(c_domain, "PAUSED", INT2NUM(VIR_DOMAIN_PAUSED));
+    rb_define_const(c_domain, "SHUTDOWN", INT2NUM(VIR_DOMAIN_SHUTDOWN));
+    rb_define_const(c_domain, "SHUTOFF", INT2NUM(VIR_DOMAIN_SHUTOFF));
+    rb_define_const(c_domain, "CRASHED", INT2NUM(VIR_DOMAIN_CRASHED));
+
+    /* virDomainMigrateFlags */
+#if HAVE_CONST_VIR_MIGRATE_LIVE
+    rb_define_const(c_domain, "MIGRATE_LIVE", INT2NUM(VIR_MIGRATE_LIVE));
+#endif
+#if HAVE_CONST_VIR_MIGRATE_PEER2PEER
+    rb_define_const(c_domain, "MIGRATE_PEER2PEER",
+                    INT2NUM(VIR_MIGRATE_PEER2PEER));
+#endif
+#if HAVE_CONST_VIR_MIGRATE_TUNNELLED
+    rb_define_const(c_domain, "MIGRATE_TUNNELLED",
+                    INT2NUM(VIR_MIGRATE_TUNNELLED));
+#endif
+#if HAVE_CONST_VIR_MIGRATE_PERSIST_DEST
+    rb_define_const(c_domain, "MIGRATE_PERSIST_DEST",
+                    INT2NUM(VIR_MIGRATE_PERSIST_DEST));
+#endif
+#if HAVE_CONST_VIR_MIGRATE_UNDEFINE_SOURCE
+    rb_define_const(c_domain, "MIGRATE_UNDEFINE_SOURCE",
+                    INT2NUM(VIR_MIGRATE_UNDEFINE_SOURCE));
+#endif
+#if HAVE_CONST_VIR_MIGRATE_PAUSED
+    rb_define_const(c_domain, "MIGRATE_PAUSED", INT2NUM(VIR_MIGRATE_PAUSED));
+#endif
+#if HAVE_CONST_VIR_MIGRATE_NON_SHARED_DISK
+    rb_define_const(c_domain, "MIGRATE_NON_SHARED_DISK",
+                    INT2NUM(VIR_MIGRATE_NON_SHARED_DISK));
+#endif
+#if HAVE_CONST_VIR_MIGRATE_NON_SHARED_INC
+    rb_define_const(c_domain, "MIGRATE_NON_SHARED_INC",
+                    INT2NUM(VIR_MIGRATE_NON_SHARED_INC));
+#endif
+    rb_define_const(c_domain, "DOMAIN_XML_SECURE",
+                    INT2NUM(VIR_DOMAIN_XML_SECURE));
+    rb_define_const(c_domain, "DOMAIN_XML_INACTIVE",
+                    INT2NUM(VIR_DOMAIN_XML_INACTIVE));
+#if HAVE_CONST_VIR_DOMAIN_XML_UPDATE_CPU
+    rb_define_const(c_domain, "DOMAIN_XML_UPDATE_CPU",
+                    INT2NUM(VIR_DOMAIN_XML_UPDATE_CPU));
+#endif
+#if HAVE_VIRDOMAINMEMORYPEEK
+    rb_define_const(c_domain, "MEMORY_VIRTUAL", INT2NUM(VIR_MEMORY_VIRTUAL));
+#endif
+#if HAVE_CONST_VIR_MEMORY_PHYSICAL
+    rb_define_const(c_domain, "MEMORY_PHYSICAL", INT2NUM(VIR_MEMORY_PHYSICAL));
+#endif
+
+#if HAVE_CONST_VIR_DOMAIN_START_PAUSED
+    rb_define_const(c_domain, "START_PAUSED", INT2NUM(VIR_DOMAIN_START_PAUSED));
+#endif
+
+#if HAVE_CONST_VIR_DUMP_CRASH
+    rb_define_const(c_domain, "DUMP_CRASH", INT2NUM(VIR_DUMP_CRASH));
+#endif
+#if HAVE_CONST_VIR_DUMP_LIVE
+    rb_define_const(c_domain, "DUMP_LIVE", INT2NUM(VIR_DUMP_LIVE));
+#endif
+
+#if HAVE_VIRDOMAINGETVCPUSFLAGS
+    rb_define_const(c_domain, "VCPU_LIVE", INT2NUM(VIR_DOMAIN_VCPU_LIVE));
+    rb_define_const(c_domain, "VCPU_CONFIG", INT2NUM(VIR_DOMAIN_VCPU_CONFIG));
+    rb_define_const(c_domain, "VCPU_MAXIMUM", INT2NUM(VIR_DOMAIN_VCPU_MAXIMUM));
+#endif
+
+    rb_define_method(c_domain, "migrate", libvirt_dom_migrate, -1);
+#if HAVE_VIRDOMAINMIGRATETOURI
+    rb_define_method(c_domain, "migrate_to_uri",
+                     libvirt_dom_migrate_to_uri, -1);
+#endif
+#if HAVE_VIRDOMAINMIGRATESETMAXDOWNTIME
+    rb_define_method(c_domain, "migrate_set_max_downtime",
+                     libvirt_dom_migrate_set_max_downtime, -1);
+#endif
+#if HAVE_VIRDOMAINMIGRATE2
+    rb_define_method(c_domain, "migrate2", libvirt_dom_migrate2, -1);
+    rb_define_method(c_domain, "migrate_to_uri2",
+                     libvirt_dom_migrate_to_uri2, -1);
+    rb_define_method(c_domain, "migrate_set_max_speed",
+                     libvirt_dom_migrate_set_max_speed, -1);
+#endif
+
+    rb_define_attr(c_domain, "connection", 1, 0);
+    rb_define_method(c_domain, "shutdown", libvirt_dom_shutdown, 0);
+    rb_define_method(c_domain, "reboot", libvirt_dom_reboot, -1);
+    rb_define_method(c_domain, "destroy", libvirt_dom_destroy, 0);
+    rb_define_method(c_domain, "suspend", libvirt_dom_suspend, 0);
+    rb_define_method(c_domain, "resume", libvirt_dom_resume, 0);
+    rb_define_method(c_domain, "save", libvirt_dom_save, 1);
+    rb_define_singleton_method(c_domain, "restore", libvirt_dom_s_restore, 2);
+    rb_define_method(c_domain, "restore", libvirt_dom_restore, 1);
+    rb_define_method(c_domain, "core_dump", libvirt_dom_core_dump, -1);
+    rb_define_method(c_domain, "info", libvirt_dom_info, 0);
+    rb_define_method(c_domain, "ifinfo", libvirt_dom_if_stats, 1);
+    rb_define_method(c_domain, "name", libvirt_dom_name, 0);
+    rb_define_method(c_domain, "id", libvirt_dom_id, 0);
+    rb_define_method(c_domain, "uuid", libvirt_dom_uuid, 0);
+    rb_define_method(c_domain, "os_type", libvirt_dom_os_type, 0);
+    rb_define_method(c_domain, "max_memory", libvirt_dom_max_memory, 0);
+    rb_define_method(c_domain, "max_memory=", libvirt_dom_max_memory_set, 1);
+    rb_define_method(c_domain, "memory=", libvirt_dom_memory_set, 1);
+    rb_define_method(c_domain, "max_vcpus", libvirt_dom_max_vcpus, 0);
+    rb_define_method(c_domain, "vcpus=", libvirt_dom_vcpus_set, 1);
+#if HAVE_VIRDOMAINSETVCPUSFLAGS
+    rb_define_method(c_domain, "vcpus_flags=", libvirt_dom_vcpus_set_flags, 1);
+#endif
+    rb_define_method(c_domain, "pin_vcpu", libvirt_dom_pin_vcpu, 2);
+    rb_define_method(c_domain, "xml_desc", libvirt_dom_xml_desc, -1);
+    rb_define_method(c_domain, "undefine", libvirt_dom_undefine, 0);
+    rb_define_method(c_domain, "create", libvirt_dom_create, -1);
+    rb_define_method(c_domain, "autostart", libvirt_dom_autostart, 0);
+    rb_define_method(c_domain, "autostart?", libvirt_dom_autostart, 0);
+    rb_define_method(c_domain, "autostart=", libvirt_dom_autostart_set, 1);
+    rb_define_method(c_domain, "free", libvirt_dom_free, 0);
+
+#if HAVE_CONST_VIR_DOMAIN_DEVICE_MODIFY_CURRENT
+    rb_define_const(c_domain, "DEVICE_MODIFY_CURRENT",
+                    INT2NUM(VIR_DOMAIN_DEVICE_MODIFY_CURRENT));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_DEVICE_MODIFY_LIVE
+    rb_define_const(c_domain, "DEVICE_MODIFY_LIVE",
+                    INT2NUM(VIR_DOMAIN_DEVICE_MODIFY_LIVE));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_DEVICE_MODIFY_CONFIG
+    rb_define_const(c_domain, "DEVICE_MODIFY_CONFIG",
+                    INT2NUM(VIR_DOMAIN_DEVICE_MODIFY_CONFIG));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_DEVICE_MODIFY_FORCE
+    rb_define_const(c_domain, "DEVICE_MODIFY_FORCE",
+                    INT2NUM(VIR_DOMAIN_DEVICE_MODIFY_FORCE));
+#endif
+    rb_define_method(c_domain, "attach_device", libvirt_dom_attach_device, -1);
+    rb_define_method(c_domain, "detach_device", libvirt_dom_detach_device, -1);
+#if HAVE_VIRDOMAINUPDATEDEVICEFLAGS
+    rb_define_method(c_domain, "update_device", libvirt_dom_update_device, -1);
+#endif
+
+    rb_define_method(c_domain, "scheduler_type", libvirt_dom_scheduler_type, 0);
+
+#if HAVE_VIRDOMAINMANAGEDSAVE
+    rb_define_method(c_domain, "managed_save", libvirt_dom_managed_save, -1);
+    rb_define_method(c_domain, "has_managed_save?",
+                     libvirt_dom_has_managed_save, -1);
+    rb_define_method(c_domain, "managed_save_remove",
+                     libvirt_dom_managed_save_remove, -1);
+#endif
+#if HAVE_VIRDOMAINGETSECURITYLABEL
+    rb_define_method(c_domain, "security_label",
+                     libvirt_dom_security_label, 0);
+#endif
+    rb_define_method(c_domain, "block_stats", libvirt_dom_block_stats, 1);
+#if HAVE_TYPE_VIRDOMAINMEMORYSTATPTR
+    rb_define_method(c_domain, "memory_stats", libvirt_dom_memory_stats, -1);
+#endif
+#if HAVE_VIRDOMAINBLOCKPEEK
+    rb_define_method(c_domain, "block_peek", libvirt_dom_block_peek, -1);
+#endif
+#if HAVE_TYPE_VIRDOMAINBLOCKINFOPTR
+    rb_define_method(c_domain, "blockinfo", libvirt_dom_block_info, -1);
+#endif
+#if HAVE_VIRDOMAINMEMORYPEEK
+    rb_define_method(c_domain, "memory_peek", libvirt_dom_memory_peek, -1);
+#endif
+    rb_define_method(c_domain, "get_vcpus", libvirt_dom_get_vcpus, 0);
+#if HAVE_VIRDOMAINISACTIVE
+    rb_define_method(c_domain, "active?", libvirt_dom_active_p, 0);
+#endif
+#if HAVE_VIRDOMAINISPERSISTENT
+    rb_define_method(c_domain, "persistent?", libvirt_dom_persistent_p, 0);
+#endif
+#if HAVE_TYPE_VIRDOMAINSNAPSHOTPTR
+    rb_define_method(c_domain, "snapshot_create_xml",
+                     libvirt_dom_snapshot_create_xml, -1);
+    rb_define_method(c_domain, "num_of_snapshots",
+                     libvirt_dom_num_of_snapshots, -1);
+    rb_define_method(c_domain, "list_snapshots",
+                     libvirt_dom_list_snapshots, -1);
+    rb_define_method(c_domain, "lookup_snapshot_by_name",
+                     libvirt_dom_lookup_snapshot_by_name, -1);
+    rb_define_method(c_domain, "has_current_snapshot?",
+                     libvirt_dom_has_current_snapshot_p, -1);
+    rb_define_method(c_domain, "revert_to_snapshot",
+                     libvirt_dom_revert_to_snapshot, -1);
+    rb_define_method(c_domain, "current_snapshot",
+                     libvirt_dom_current_snapshot, -1);
+#endif
+
+    /*
+     * Class Libvirt::Domain::Info
+     */
+    c_domain_info = rb_define_class_under(c_domain, "Info", rb_cObject);
+    rb_define_attr(c_domain_info, "state", 1, 0);
+    rb_define_attr(c_domain_info, "max_mem", 1, 0);
+    rb_define_attr(c_domain_info, "memory", 1, 0);
+    rb_define_attr(c_domain_info, "nr_virt_cpu", 1, 0);
+    rb_define_attr(c_domain_info, "cpu_time", 1, 0);
+
+    /*
+     * Class Libvirt::Domain::InterfaceInfo
+     */
+    c_domain_ifinfo = rb_define_class_under(c_domain, "InterfaceInfo",
+                                            rb_cObject);
+    rb_define_attr(c_domain_ifinfo, "rx_bytes", 1, 0);
+    rb_define_attr(c_domain_ifinfo, "rx_packets", 1, 0);
+    rb_define_attr(c_domain_ifinfo, "rx_errs", 1, 0);
+    rb_define_attr(c_domain_ifinfo, "rx_drop", 1, 0);
+    rb_define_attr(c_domain_ifinfo, "tx_bytes", 1, 0);
+    rb_define_attr(c_domain_ifinfo, "tx_packets", 1, 0);
+    rb_define_attr(c_domain_ifinfo, "tx_errs", 1, 0);
+    rb_define_attr(c_domain_ifinfo, "tx_drop", 1, 0);
+
+    /*
+     * Class Libvirt::Domain::SecurityLabel
+     */
+    c_domain_security_label = rb_define_class_under(c_domain, "SecurityLabel",
+                                                    rb_cObject);
+    rb_define_attr(c_domain_security_label, "label", 1, 0);
+    rb_define_attr(c_domain_security_label, "enforcing", 1, 0);
+
+    /*
+     * Class Libvirt::Domain::BlockStats
+     */
+    c_domain_block_stats = rb_define_class_under(c_domain, "BlockStats",
+                                                 rb_cObject);
+    rb_define_attr(c_domain_block_stats, "rd_req", 1, 0);
+    rb_define_attr(c_domain_block_stats, "rd_bytes", 1, 0);
+    rb_define_attr(c_domain_block_stats, "wr_req", 1, 0);
+    rb_define_attr(c_domain_block_stats, "wr_bytes", 1, 0);
+    rb_define_attr(c_domain_block_stats, "errs", 1, 0);
+
+#if HAVE_TYPE_VIRDOMAINMEMORYSTATPTR
+    /*
+     * Class Libvirt::Domain::MemoryStats
+     */
+    c_domain_memory_stats = rb_define_class_under(c_domain, "MemoryStats",
+                                                  rb_cObject);
+    rb_define_attr(c_domain_memory_stats, "tag", 1, 0);
+    rb_define_attr(c_domain_memory_stats, "value", 1, 0);
+
+    rb_define_const(c_domain_memory_stats, "SWAP_IN",
+                    INT2NUM(VIR_DOMAIN_MEMORY_STAT_SWAP_IN));
+    rb_define_const(c_domain_memory_stats, "SWAP_OUT",
+                    INT2NUM(VIR_DOMAIN_MEMORY_STAT_SWAP_OUT));
+    rb_define_const(c_domain_memory_stats, "MAJOR_FAULT",
+                    INT2NUM(VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT));
+    rb_define_const(c_domain_memory_stats, "MINOR_FAULT",
+                    INT2NUM(VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT));
+    rb_define_const(c_domain_memory_stats, "UNUSED",
+                    INT2NUM(VIR_DOMAIN_MEMORY_STAT_UNUSED));
+    rb_define_const(c_domain_memory_stats, "AVAILABLE",
+                    INT2NUM(VIR_DOMAIN_MEMORY_STAT_AVAILABLE));
+    rb_define_const(c_domain_memory_stats, "NR",
+                    INT2NUM(VIR_DOMAIN_MEMORY_STAT_NR));
+#endif
+
+#if HAVE_TYPE_VIRDOMAINBLOCKINFOPTR
+    /*
+     * Class Libvirt::Domain::BlockInfo
+     */
+    c_domain_block_info = rb_define_class_under(c_domain, "BlockInfo",
+                                                rb_cObject);
+    rb_define_attr(c_domain_block_info, "capacity", 1, 0);
+    rb_define_attr(c_domain_block_info, "allocation", 1, 0);
+    rb_define_attr(c_domain_block_info, "physical", 1, 0);
+#endif
+
+#if HAVE_TYPE_VIRDOMAINSNAPSHOTPTR
+    /*
+     * Class Libvirt::Domain::Snapshot
+     */
+    c_domain_snapshot = rb_define_class_under(c_domain, "Snapshot", rb_cObject);
+    rb_define_const(c_domain_snapshot, "DELETE_CHILDREN",
+                    INT2NUM(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN));
+    rb_define_method(c_domain_snapshot, "xml_desc",
+                     libvirt_dom_snapshot_xml_desc, -1);
+    rb_define_method(c_domain_snapshot, "delete",
+                     libvirt_dom_snapshot_delete, -1);
+    rb_define_method(c_domain_snapshot, "free", libvirt_dom_snapshot_free, 0);
+#endif
+
+    /*
+     * Class Libvirt::Domain::VCPUInfo
+     */
+    c_domain_vcpuinfo = rb_define_class_under(c_domain, "VCPUInfo", rb_cObject);
+    rb_define_const(c_domain_vcpuinfo, "OFFLINE", VIR_VCPU_OFFLINE);
+    rb_define_const(c_domain_vcpuinfo, "RUNNING", VIR_VCPU_RUNNING);
+    rb_define_const(c_domain_vcpuinfo, "BLOCKED", VIR_VCPU_BLOCKED);
+    rb_define_attr(c_domain_vcpuinfo, "number", 1, 0);
+    rb_define_attr(c_domain_vcpuinfo, "state", 1, 0);
+    rb_define_attr(c_domain_vcpuinfo, "cpu_time", 1, 0);
+    rb_define_attr(c_domain_vcpuinfo, "cpu", 1, 0);
+    rb_define_attr(c_domain_vcpuinfo, "cpumap", 1, 0);
+
+#if HAVE_TYPE_VIRDOMAINJOBINFOPTR
+    /*
+     * Class Libvirt::Domain::JobInfo
+     */
+    c_domain_job_info = rb_define_class_under(c_domain, "JobInfo", rb_cObject);
+    rb_define_const(c_domain_job_info, "NONE", INT2NUM(VIR_DOMAIN_JOB_NONE));
+    rb_define_const(c_domain_job_info, "BOUNDED",
+                    INT2NUM(VIR_DOMAIN_JOB_BOUNDED));
+    rb_define_const(c_domain_job_info, "UNBOUNDED",
+                    INT2NUM(VIR_DOMAIN_JOB_UNBOUNDED));
+    rb_define_const(c_domain_job_info, "COMPLETED",
+                    INT2NUM(VIR_DOMAIN_JOB_COMPLETED));
+    rb_define_const(c_domain_job_info, "FAILED",
+                    INT2NUM(VIR_DOMAIN_JOB_FAILED));
+    rb_define_const(c_domain_job_info, "CANCELLED",
+                    INT2NUM(VIR_DOMAIN_JOB_CANCELLED));
+    rb_define_attr(c_domain_job_info, "type", 1, 0);
+    rb_define_attr(c_domain_job_info, "time_elapsed", 1, 0);
+    rb_define_attr(c_domain_job_info, "time_remaining", 1, 0);
+    rb_define_attr(c_domain_job_info, "data_total", 1, 0);
+    rb_define_attr(c_domain_job_info, "data_processed", 1, 0);
+    rb_define_attr(c_domain_job_info, "data_remaining", 1, 0);
+    rb_define_attr(c_domain_job_info, "mem_total", 1, 0);
+    rb_define_attr(c_domain_job_info, "mem_processed", 1, 0);
+    rb_define_attr(c_domain_job_info, "mem_remaining", 1, 0);
+    rb_define_attr(c_domain_job_info, "file_total", 1, 0);
+    rb_define_attr(c_domain_job_info, "file_processed", 1, 0);
+    rb_define_attr(c_domain_job_info, "file_remaining", 1, 0);
+
+    rb_define_method(c_domain, "job_info", libvirt_dom_job_info, 0);
+    rb_define_method(c_domain, "abort_job", libvirt_dom_abort_job, 0);
+#endif
+
+#if HAVE_VIRDOMAINQEMUMONITORCOMMAND
+    rb_define_method(c_domain, "qemu_monitor_command",
+                     libvirt_dom_qemu_monitor_command, -1);
+#endif
+
+#if HAVE_VIRDOMAINGETVCPUSFLAGS
+    rb_define_method(c_domain, "num_vcpus", libvirt_dom_num_vcpus, 1);
+#endif
+
+#if HAVE_VIRDOMAINISUPDATED
+    rb_define_method(c_domain, "updated?", libvirt_dom_is_updated, 0);
+#endif
+
+#ifdef VIR_DOMAIN_MEMORY_PARAM_UNLIMITED
+    rb_define_const(c_domain, "MEMORY_PARAM_UNLIMITED",
+                    VIR_DOMAIN_MEMORY_PARAM_UNLIMITED);
+#endif
+
+#if HAVE_VIRDOMAINSETMEMORYFLAGS
+    rb_define_const(c_domain, "DOMAIN_MEM_LIVE", INT2NUM(VIR_DOMAIN_MEM_LIVE));
+    rb_define_const(c_domain, "DOMAIN_MEM_CONFIG",
+                    INT2NUM(VIR_DOMAIN_MEM_CONFIG));
+#endif
+#if HAVE_CONST_VIR_DOMAIN_MEM_CURRENT
+    rb_define_const(c_domain, "DOMAIN_MEM_CURRENT",
+                    INT2NUM(VIR_DOMAIN_MEM_CURRENT));
+    rb_define_const(c_domain, "DOMAIN_MEM_MAXIMUM",
+                    INT2NUM(VIR_DOMAIN_MEM_MAXIMUM));
+#endif
+
+    rb_define_method(c_domain, "scheduler_parameters",
+                     libvirt_dom_get_scheduler_parameters, -1);
+    rb_define_method(c_domain, "scheduler_parameters=",
+                     libvirt_dom_set_scheduler_parameters, 1);
+
+#if HAVE_VIRDOMAINSETMEMORYPARAMETERS
+    rb_define_method(c_domain, "memory_parameters",
+                     libvirt_dom_get_memory_parameters, -1);
+    rb_define_method(c_domain, "memory_parameters=",
+                     libvirt_dom_set_memory_parameters, 1);
+#endif
+
+#if HAVE_VIRDOMAINSETBLKIOPARAMETERS
+    rb_define_method(c_domain, "blkio_parameters",
+                     libvirt_dom_get_blkio_parameters, -1);
+    rb_define_method(c_domain, "blkio_parameters=",
+                     libvirt_dom_set_blkio_parameters, 1);
+#endif
+
+#if HAVE_VIRDOMAINGETSTATE
+    rb_define_const(c_domain, "DOMAIN_RUNNING_UNKNOWN",
+                    INT2NUM(VIR_DOMAIN_RUNNING_UNKNOWN));
+    rb_define_const(c_domain, "DOMAIN_RUNNING_BOOTED",
+                    INT2NUM(VIR_DOMAIN_RUNNING_BOOTED));
+    rb_define_const(c_domain, "DOMAIN_RUNNING_MIGRATED",
+                    INT2NUM(VIR_DOMAIN_RUNNING_MIGRATED));
+    rb_define_const(c_domain, "DOMAIN_RUNNING_RESTORED",
+                    INT2NUM(VIR_DOMAIN_RUNNING_RESTORED));
+    rb_define_const(c_domain, "DOMAIN_RUNNING_FROM_SNAPSHOT",
+                    INT2NUM(VIR_DOMAIN_RUNNING_FROM_SNAPSHOT));
+    rb_define_const(c_domain, "DOMAIN_RUNNING_UNPAUSED",
+                    INT2NUM(VIR_DOMAIN_RUNNING_UNPAUSED));
+    rb_define_const(c_domain, "DOMAIN_RUNNING_MIGRATION_CANCELED",
+                    INT2NUM(VIR_DOMAIN_RUNNING_MIGRATION_CANCELED));
+    rb_define_const(c_domain, "DOMAIN_RUNNING_SAVE_CANCELED",
+                    INT2NUM(VIR_DOMAIN_RUNNING_SAVE_CANCELED));
+    rb_define_const(c_domain, "DOMAIN_BLOCKED_UNKNOWN",
+                    INT2NUM(VIR_DOMAIN_BLOCKED_UNKNOWN));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_UNKNOWN",
+                    INT2NUM(VIR_DOMAIN_PAUSED_UNKNOWN));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_USER",
+                    INT2NUM(VIR_DOMAIN_PAUSED_USER));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_MIGRATION",
+                    INT2NUM(VIR_DOMAIN_PAUSED_MIGRATION));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_SAVE",
+                    INT2NUM(VIR_DOMAIN_PAUSED_SAVE));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_DUMP",
+                    INT2NUM(VIR_DOMAIN_PAUSED_DUMP));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_IOERROR",
+                    INT2NUM(VIR_DOMAIN_PAUSED_IOERROR));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_WATCHDOG",
+                    INT2NUM(VIR_DOMAIN_PAUSED_WATCHDOG));
+    rb_define_const(c_domain, "DOMAIN_PAUSED_FROM_SNAPSHOT",
+                    INT2NUM(VIR_DOMAIN_PAUSED_FROM_SNAPSHOT));
+    rb_define_const(c_domain, "DOMAIN_SHUTDOWN_UNKNOWN",
+                    INT2NUM(VIR_DOMAIN_SHUTDOWN_UNKNOWN));
+    rb_define_const(c_domain, "DOMAIN_SHUTDOWN_USER",
+                    INT2NUM(VIR_DOMAIN_SHUTDOWN_USER));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_UNKNOWN",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_UNKNOWN));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_SHUTDOWN",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_SHUTDOWN));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_DESTROYED",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_DESTROYED));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_CRASHED",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_CRASHED));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_MIGRATED",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_MIGRATED));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_SAVED",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_SAVED));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_FAILED",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_FAILED));
+    rb_define_const(c_domain, "DOMAIN_SHUTOFF_FROM_SNAPSHOT",
+                    INT2NUM(VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT));
+    rb_define_const(c_domain, "DOMAIN_CRASHED_UNKNOWN",
+                    INT2NUM(VIR_DOMAIN_CRASHED_UNKNOWN));
+
+    rb_define_method(c_domain, "state", libvirt_dom_get_state, -1);
+#endif
+
+#if HAVE_CONST_VIR_DOMAIN_AFFECT_CURRENT
+    rb_define_const(c_domain, "DOMAIN_AFFECT_CURRENT",
+                    INT2NUM(VIR_DOMAIN_AFFECT_CURRENT));
+    rb_define_const(c_domain, "DOMAIN_AFFECT_LIVE",
+                    INT2NUM(VIR_DOMAIN_AFFECT_LIVE));
+    rb_define_const(c_domain, "DOMAIN_AFFECT_CONFIG",
+                    INT2NUM(VIR_DOMAIN_AFFECT_CONFIG));
+#endif
+
+#if HAVE_VIRDOMAINOPENCONSOLE
+    rb_define_method(c_domain, "open_console", libvirt_dom_open_console, -1);
+#endif
+
+#if HAVE_VIRDOMAINSCREENSHOT
+    rb_define_method(c_domain, "screenshot", libvirt_dom_screenshot, -1);
+#endif
+
+#if HAVE_VIRDOMAININJECTNMI
+    rb_define_method(c_domain, "inject_nmi", libvirt_dom_inject_nmi, -1);
+#endif
+}
diff --git a/ext/libvirt/domain.h b/ext/libvirt/domain.h
new file mode 100644
index 0000000..dfca6ec
--- /dev/null
+++ b/ext/libvirt/domain.h
@@ -0,0 +1,9 @@
+#ifndef DOMAIN_H
+#define DOMAIN_H
+
+VALUE domain_new(virDomainPtr d, VALUE conn);
+virDomainPtr domain_get(VALUE s);
+
+void init_domain();
+
+#endif
diff --git a/ext/libvirt/extconf.h b/ext/libvirt/extconf.h
deleted file mode 100644
index 29a7f7c..0000000
--- a/ext/libvirt/extconf.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef EXTCONF_H
-#define EXTCONF_H
-#define HAVE_TYPE_VIRNETWORKPTR 1
-#define HAVE_TYPE_VIRSTORAGEPOOLPTR 1
-#define HAVE_TYPE_VIRSTORAGEVOLPTR 1
-#endif
diff --git a/ext/libvirt/extconf.rb b/ext/libvirt/extconf.rb
index 331eb21..6d0f6bc 100644
--- a/ext/libvirt/extconf.rb
+++ b/ext/libvirt/extconf.rb
@@ -1,5 +1,7 @@
 require 'mkmf'
 
+RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
+
 def have_libvirt_funcs(funcs)
     funcs.each { |f| have_func(f, "libvirt/libvirt.h") }
 end
@@ -8,19 +10,212 @@ def have_libvirt_types(types)
     types.each { |t| have_type(t, "libvirt/libvirt.h") }
 end
 
+# older mkmf does not have checking_message, so implement our own here
+def libvirt_checking_message(target, place = nil, opt = nil)
+  [["in", place], ["with", opt]].inject("#{target}") do |msg, (pre, noun)|
+    if noun
+      [[:to_str], [:join, ","], [:to_s]].each do |meth, *args|
+        if noun.respond_to?(meth)
+          break noun = noun.send(meth, *args)
+        end
+      end
+      msg << " #{pre} #{noun}" unless noun.empty?
+    end
+    msg
+  end
+end
+
+def have_const(const, headers = nil, opt = "", &b)
+  checking_for libvirt_checking_message(const, headers, opt) do
+    headers = cpp_include(headers)
+    if try_compile(<<"SRC", opt, &b)
+#{COMMON_HEADERS}
+#{headers}
+/*top*/
+static int t = #{const};
+SRC
+      $defs.push(format("-DHAVE_CONST_%s", const.strip.upcase.tr_s("^A-Z0-9_", "_")))
+      true
+    else
+      false
+    end
+  end
+end
+
+def have_libvirt_consts(consts)
+  consts.each { |c| have_const(c, ["libvirt/libvirt.h", "libvirt/virterror.h"]) }
+end
+
 extension_name = '_libvirt'
 
-dir_config(extension_name)
+# this is a poor-man's dir_config, but is a bit more flexible.  In particular,
+# it allows you to specify the exact location of the libvirt.so, as opposed
+# to requiring a lib/ subdirectory.  Note that due to the way include files
+# are done within ruby-libvirt, the libvirt header file(s) must be in a libvirt/
+# subdirectory.  Also note that if specifying the include directory, the
+# location of the library must also be specified.  Finally, note that if neither
+# the include nor the library are specified, the build will attempt to use
+# pkg-config to discover this information.
+#
+# Taking all of the above rules into account, the valid options are either:
+#   $ ruby extconf.rb --with-libvirt-include=/home/clalance/libvirt/include \
+#          --with-libvirt-lib=/home/clalance/libvirt/src/.libs
+#
+# To specify the location of the include files and the library, or:
+#   $ ruby extconf.rb
+#
+# to attempt to use pkg-config to do it automatically from the system files.
+include = with_config("libvirt-include")
+lib = with_config("libvirt-lib")
+if include and lib
+  $LIBPATH = [lib] | $LIBPATH
+  $CPPFLAGS += "-I" + include
+  have_library("virt", "virConnectOpen", "libvirt/libvirt.h")
 
-unless pkg_config("libvirt")
-    raise "libvirt not found"
+  # if we are using custom libvirt libraries, we have to suppress the default
+  # library path so have_func() only picks up the custom ones, not the installed
+  # ones
+  $DEFLIBPATH = []
+elsif (include and not lib) or (not include and lib)
+  raise "Must specify both --with-libvirt-include and --with-libvirt-lib, or neither"
+else
+  unless pkg_config("libvirt")
+    raise "libvirt library not found in default locations"
+  end
 end
 
+
 libvirt_types = [ 'virNetworkPtr',
                   'virStoragePoolPtr',
-                  'virStorageVolPtr' ]
+                  'virStorageVolPtr',
+                  'virSecretPtr',
+                  'virNWFilterPtr',
+                  'virInterfacePtr',
+                  'virDomainBlockInfoPtr',
+                  'virDomainMemoryStatPtr',
+                  'virDomainSnapshotPtr',
+                  'virDomainJobInfoPtr',
+                  'virNodeDevicePtr',
+                  'virStreamPtr',
+                  'virTypedParameterPtr',
+                ]
+
+libvirt_funcs = [ 'virStorageVolWipe',
+                  'virStoragePoolIsActive',
+                  'virStoragePoolIsPersistent',
+                  'virStorageVolCreateXMLFrom',
+                  'virConnectGetLibVersion',
+                  'virConnectIsEncrypted',
+                  'virConnectIsSecure',
+                  'virNetworkIsActive',
+                  'virNetworkIsPersistent',
+                  'virNodeDeviceCreateXML',
+                  'virNodeDeviceDestroy',
+                  'virInterfaceIsActive',
+                  'virDomainMigrateToURI',
+                  'virDomainMigrateSetMaxDowntime',
+                  'virDomainManagedSave',
+                  'virDomainIsActive',
+                  'virDomainIsPersistent',
+                  'virConnectDomainXMLFromNative',
+                  'virConnectDomainXMLToNative',
+                  'virDomainCreateWithFlags',
+                  'virDomainAttachDeviceFlags',
+                  'virDomainDetachDeviceFlags',
+                  'virDomainUpdateDeviceFlags',
+                  'virNodeGetSecurityModel',
+                  'virDomainCreateXML',
+                  'virDomainGetSecurityLabel',
+                  'virConnectCompareCPU',
+                  'virConnectBaselineCPU',
+                  'virDomainSetVcpusFlags',
+                  'virDomainGetVcpusFlags',
+                  'virConnectDomainEventRegisterAny',
+                  'virConnectDomainEventRegister',
+                  'virDomainBlockPeek',
+                  'virDomainMemoryPeek',
+                  'virConnectOpenAuth',
+                  'virEventRegisterImpl',
+                  'virDomainIsUpdated',
+                  'virDomainSetMemoryParameters',
+                  'virConnectGetSysinfo',
+                  'virDomainSetBlkioParameters',
+                  'virDomainSetMemoryFlags',
+                  'virDomainGetState',
+                  'virDomainOpenConsole',
+                  'virDomainMigrate2',
+                  'virDomainScreenshot',
+                  'virInterfaceChangeBegin',
+                  'virStorageVolDownload',
+                  'virDomainInjectNMI',
+                ]
+
+libvirt_consts = [ 'VIR_MIGRATE_LIVE',
+                   'VIR_MIGRATE_PEER2PEER',
+                   'VIR_MIGRATE_TUNNELLED',
+                   'VIR_MIGRATE_PERSIST_DEST',
+                   'VIR_MIGRATE_UNDEFINE_SOURCE',
+                   'VIR_MIGRATE_PAUSED',
+                   'VIR_MIGRATE_NON_SHARED_DISK',
+                   'VIR_MIGRATE_NON_SHARED_INC',
+                   'VIR_DOMAIN_XML_UPDATE_CPU',
+                   'VIR_MEMORY_PHYSICAL',
+                   'VIR_DOMAIN_START_PAUSED',
+                   'VIR_DUMP_CRASH',
+                   'VIR_DUMP_LIVE',
+                   'VIR_DOMAIN_DEVICE_MODIFY_CURRENT',
+                   'VIR_DOMAIN_DEVICE_MODIFY_LIVE',
+                   'VIR_DOMAIN_DEVICE_MODIFY_CONFIG',
+                   'VIR_DOMAIN_DEVICE_MODIFY_FORCE',
+                   'VIR_INTERFACE_XML_INACTIVE',
+                   'VIR_STORAGE_POOL_INACCESSIBLE',
+                   'VIR_DOMAIN_EVENT_DEFINED',
+                   'VIR_DOMAIN_EVENT_STARTED',
+                   'VIR_DOMAIN_EVENT_SUSPENDED_IOERROR',
+                   'VIR_DOMAIN_EVENT_ID_WATCHDOG',
+                   'VIR_DOMAIN_EVENT_ID_IO_ERROR',
+                   'VIR_DOMAIN_EVENT_ID_GRAPHICS',
+                   'VIR_DOMAIN_EVENT_ID_REBOOT',
+                   'VIR_DOMAIN_EVENT_ID_RTC_CHANGE',
+                   'VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON',
+                   'VIR_FROM_VMWARE',
+                   'VIR_FROM_AUDIT',
+                   'VIR_FROM_SYSINFO',
+                   'VIR_FROM_STREAMS',
+                   'VIR_FROM_XENAPI',
+                   'VIR_FROM_HOOK',
+                   'VIR_ERR_HOOK_SCRIPT_FAILED',
+                   'VIR_ERR_MIGRATE_PERSIST_FAILED',
+                   'VIR_ERR_OPERATION_TIMEOUT',
+                   'VIR_ERR_CONFIG_UNSUPPORTED',
+                   'VIR_FROM_XENXM',
+                   'VIR_ERR_OPERATION_INVALID',
+                   'VIR_ERR_NO_SECURITY_MODEL',
+                   'VIR_ERR_AUTH_FAILED',
+                   'VIR_FROM_PHYP',
+                   'VIR_FROM_ESX',
+                   'VIR_FROM_ONE',
+                   'VIR_FROM_VBOX',
+                   'VIR_FROM_LXC',
+                   'VIR_FROM_UML',
+                   'VIR_FROM_NETWORK',
+                   'VIR_FROM_DOMAIN',
+                   'VIR_FROM_STATS_LINUX',
+                   'VIR_FROM_XEN_INOTIFY',
+                   'VIR_FROM_SECURITY',
+                   'VIR_DOMAIN_AFFECT_CURRENT',
+                   'VIR_DOMAIN_MEM_CURRENT',
+                   'VIR_DOMAIN_EVENT_ID_CONTROL_ERROR',
+                 ]
 
 have_libvirt_types(libvirt_types)
+have_libvirt_funcs(libvirt_funcs)
+if find_header("libvirt/libvirt-qemu.h")
+  have_library("virt-qemu", "virDomainQemuMonitorCommand")
+  have_func("virDomainQemuMonitorCommand", "libvirt/libvirt-qemu.h")
+end
+
+have_libvirt_consts(libvirt_consts)
 
 create_header
 create_makefile(extension_name)
diff --git a/ext/libvirt/interface.c b/ext/libvirt/interface.c
new file mode 100644
index 0000000..6af2fea
--- /dev/null
+++ b/ext/libvirt/interface.c
@@ -0,0 +1,181 @@
+/*
+ * interface.c: virInterface methods
+ *
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+
+#if HAVE_TYPE_VIRINTERFACEPTR
+static VALUE c_interface;
+
+static void interface_free(void *i) {
+    generic_free(Interface, i);
+}
+
+static virInterfacePtr interface_get(VALUE s) {
+    generic_get(Interface, s);
+}
+
+VALUE interface_new(virInterfacePtr i, VALUE conn) {
+    return generic_new(c_interface, i, conn, interface_free);
+}
+
+/*
+ * call-seq:
+ *   interface.undefine -> nil
+ *
+ * Call +virInterfaceUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceUndefine]
+ * to undefine this interface.
+ */
+static VALUE libvirt_interface_undefine(VALUE s) {
+    gen_call_void(virInterfaceUndefine, conn(s), interface_get(s));
+}
+
+/*
+ * call-seq:
+ *   interface.create(flags=0) -> nil
+ *
+ * Call +virInterfaceCreate+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceCreate]
+ * to start this interface.
+ */
+static VALUE libvirt_interface_create(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virInterfaceCreate, conn(s), interface_get(s),
+                  NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   interface.destroy(flags=0) -> nil
+ *
+ * Call +virInterfaceDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceDestroy]
+ * to shutdown this interface.
+ */
+static VALUE libvirt_interface_destroy(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virInterfaceDestroy, conn(s), interface_get(s),
+                  NUM2UINT(flags));
+}
+
+#if HAVE_VIRINTERFACEISACTIVE
+/*
+ * call-seq:
+ *   interface.active? -> [true|false]
+ *
+ * Call +virInterfaceIsActive+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceIsActive]
+ * to determine if this interface is currently active.
+ */
+static VALUE libvirt_interface_active_p(VALUE p) {
+    gen_call_truefalse(virInterfaceIsActive, conn(p), interface_get(p));
+}
+#endif
+
+/*
+ * call-seq:
+ *   interface.name -> string
+ *
+ * Call +virInterfaceGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceGetName]
+ * to retrieve the name of this interface.
+ */
+static VALUE libvirt_interface_name(VALUE s) {
+    gen_call_string(virInterfaceGetName, conn(s), 0, interface_get(s));
+}
+
+/*
+ * call-seq:
+ *   interface.mac -> string
+ *
+ * Call +virInterfaceGetMACString+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceGetMACString]
+ * to retrieve the MAC address of this interface.
+ */
+static VALUE libvirt_interface_mac(VALUE s) {
+    gen_call_string(virInterfaceGetMACString, conn(s), 0, interface_get(s));
+}
+
+/*
+ * call-seq:
+ *   interface.xml_desc -> string
+ *
+ * Call +virInterfaceGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceGetXMLDesc]
+ * to retrieve the XML of this interface.
+ */
+static VALUE libvirt_interface_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virInterfaceGetXMLDesc, conn(s), 1, interface_get(s),
+                    NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   interface.free -> nil
+ *
+ * Call +virInterfaceFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virInterfaceFree]
+ * to free this interface.  The object will no longer be valid after this call.
+ */
+static VALUE libvirt_interface_free(VALUE s) {
+    gen_call_free(Interface, s);
+}
+#endif
+
+/*
+ * Class Libvirt::Interface
+ */
+void init_interface()
+{
+#if HAVE_TYPE_VIRINTERFACEPTR
+    c_interface = rb_define_class_under(m_libvirt, "Interface", rb_cObject);
+#if HAVE_CONST_VIR_INTERFACE_XML_INACTIVE
+    rb_define_const(c_interface, "XML_INACTIVE",
+                    INT2NUM(VIR_INTERFACE_XML_INACTIVE));
+#endif
+    rb_define_attr(c_interface, "connection", 1, 0);
+
+    /* Interface object methods */
+    rb_define_method(c_interface, "name", libvirt_interface_name, 0);
+    rb_define_method(c_interface, "mac", libvirt_interface_mac, 0);
+    rb_define_method(c_interface, "xml_desc", libvirt_interface_xml_desc, -1);
+    rb_define_method(c_interface, "undefine", libvirt_interface_undefine, 0);
+    rb_define_method(c_interface, "create", libvirt_interface_create, -1);
+    rb_define_method(c_interface, "destroy", libvirt_interface_destroy, -1);
+    rb_define_method(c_interface, "free", libvirt_interface_free, 0);
+#if HAVE_VIRINTERFACEISACTIVE
+    rb_define_method(c_interface, "active?", libvirt_interface_active_p, 0);
+#endif
+#endif
+}
diff --git a/ext/libvirt/interface.h b/ext/libvirt/interface.h
new file mode 100644
index 0000000..a313625
--- /dev/null
+++ b/ext/libvirt/interface.h
@@ -0,0 +1,6 @@
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+void init_interface();
+
+#endif
diff --git a/ext/libvirt/network.c b/ext/libvirt/network.c
new file mode 100644
index 0000000..75eefce
--- /dev/null
+++ b/ext/libvirt/network.c
@@ -0,0 +1,235 @@
+/*
+ * network.c: virNetwork methods
+ *
+ * Copyright (C) 2007,2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+
+#if HAVE_TYPE_VIRNETWORKPTR
+static VALUE c_network;
+
+static void network_free(void *d) {
+    generic_free(Network, d);
+}
+
+static virNetworkPtr network_get(VALUE s) {
+    generic_get(Network, s);
+}
+
+VALUE network_new(virNetworkPtr n, VALUE conn) {
+    return generic_new(c_network, n, conn, network_free);
+}
+
+/*
+ * call-seq:
+ *   net.undefine -> nil
+ *
+ * Call +virNetworkUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkUndefine]
+ * to undefine this network.
+ */
+static VALUE libvirt_netw_undefine(VALUE s) {
+    gen_call_void(virNetworkUndefine, conn(s), network_get(s));
+}
+
+/*
+ * call-seq:
+ *   net.create -> nil
+ *
+ * Call +virNetworkCreate+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkCreate]
+ * to start this network.
+ */
+static VALUE libvirt_netw_create(VALUE s) {
+    gen_call_void(virNetworkCreate, conn(s), network_get(s));
+}
+
+/*
+ * call-seq:
+ *   net.destroy -> nil
+ *
+ * Call +virNetworkDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkDestroy]
+ * to shutdown this network.
+ */
+static VALUE libvirt_netw_destroy(VALUE s) {
+    gen_call_void(virNetworkDestroy, conn(s), network_get(s));
+}
+
+/*
+ * call-seq:
+ *   net.name -> string
+ *
+ * Call +virNetworkGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetName]
+ * to retrieve the name of this network.
+ */
+static VALUE libvirt_netw_name(VALUE s) {
+    gen_call_string(virNetworkGetName, conn(s), 0, network_get(s));
+}
+
+/*
+ * call-seq:
+ *   net.uuid -> string
+ *
+ * Call +virNetworkGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetUUIDString]
+ * to retrieve the UUID of this network.
+ */
+static VALUE libvirt_netw_uuid(VALUE s) {
+    virNetworkPtr netw = network_get(s);
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    int r;
+
+    r = virNetworkGetUUIDString(netw, uuid);
+    _E(r < 0, create_error(e_RetrieveError, "virNetworkGetUUIDString",
+                           conn(s)));
+
+    return rb_str_new2((char *) uuid);
+}
+
+/*
+ * call-seq:
+ *   net.xml_desc(flags=0) -> string
+ *
+ * Call +virNetworkGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetXMLDesc]
+ * to retrieve the XML for this network.
+ */
+static VALUE libvirt_netw_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virNetworkGetXMLDesc, conn(s), 1, network_get(s),
+                    NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   net.bridge_name -> string
+ *
+ * Call +virNetworkGetBridgeName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetBridgeName]
+ * to retrieve the bridge name for this network.
+ */
+static VALUE libvirt_netw_bridge_name(VALUE s) {
+    gen_call_string(virNetworkGetBridgeName, conn(s), 1, network_get(s));
+}
+
+/*
+ * call-seq:
+ *   net.autostart? -> [true|false]
+ *
+ * Call +virNetworkGetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkGetAutostart]
+ * to determine if this network will be autostarted when libvirtd starts.
+ */
+static VALUE libvirt_netw_autostart(VALUE s){
+    virNetworkPtr netw = network_get(s);
+    int r, autostart;
+
+    r = virNetworkGetAutostart(netw, &autostart);
+    _E(r < 0, create_error(e_RetrieveError, "virNetworkAutostart", conn(s)));
+
+    return autostart ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   net.autostart = [true|false]
+ *
+ * Call +virNetworkSetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkSetAutostart]
+ * to set this network to be autostarted when libvirtd starts.
+ */
+static VALUE libvirt_netw_autostart_set(VALUE s, VALUE autostart) {
+    if (autostart != Qtrue && autostart != Qfalse)
+        rb_raise(rb_eTypeError,
+                 "wrong argument type (expected TrueClass or FalseClass)");
+
+    gen_call_void(virNetworkSetAutostart, conn(s), network_get(s),
+                  RTEST(autostart) ? 1 : 0);
+}
+
+/*
+ * call-seq:
+ *   net.free -> nil
+ *
+ * Call +virNetworkFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkFree]
+ * to free this network.  The object will no longer be valid after this call.
+ */
+static VALUE libvirt_netw_free(VALUE s) {
+    gen_call_free(Network, s);
+}
+
+#if HAVE_VIRNETWORKISACTIVE
+/*
+ * call-seq:
+ *   net.active? -> [true|false]
+ *
+ * Call +virNetworkIsActive+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkIsActive]
+ * to determine if this network is currently active.
+ */
+static VALUE libvirt_netw_active_p(VALUE s) {
+    gen_call_truefalse(virNetworkIsActive, conn(s), network_get(s));
+}
+#endif
+
+#if HAVE_VIRNETWORKISPERSISTENT
+/*
+ * call-seq:
+ *   net.persistent? -> [true|false]
+ *
+ * Call +virNetworkIsPersistent+[http://www.libvirt.org/html/libvirt-libvirt.html#virNetworkIsPersistent]
+ * to determine if this network is persistent.
+ */
+static VALUE libvirt_netw_persistent_p(VALUE s) {
+    gen_call_truefalse(virNetworkIsPersistent, conn(s), network_get(s));
+}
+#endif
+
+#endif
+
+/*
+ * Class Libvirt::Network
+ */
+void init_network()
+{
+#if HAVE_TYPE_VIRNETWORKPTR
+    c_network = rb_define_class_under(m_libvirt, "Network", rb_cObject);
+    rb_define_attr(c_network, "connection", 1, 0);
+
+    rb_define_method(c_network, "undefine", libvirt_netw_undefine, 0);
+    rb_define_method(c_network, "create", libvirt_netw_create, 0);
+    rb_define_method(c_network, "destroy", libvirt_netw_destroy, 0);
+    rb_define_method(c_network, "name", libvirt_netw_name, 0);
+    rb_define_method(c_network, "uuid", libvirt_netw_uuid, 0);
+    rb_define_method(c_network, "xml_desc", libvirt_netw_xml_desc, -1);
+    rb_define_method(c_network, "bridge_name", libvirt_netw_bridge_name, 0);
+    rb_define_method(c_network, "autostart", libvirt_netw_autostart, 0);
+    rb_define_method(c_network, "autostart?", libvirt_netw_autostart, 0);
+    rb_define_method(c_network, "autostart=", libvirt_netw_autostart_set, 1);
+    rb_define_method(c_network, "free", libvirt_netw_free, 0);
+#if HAVE_VIRNETWORKISACTIVE
+    rb_define_method(c_network, "active?", libvirt_netw_active_p, 0);
+#endif
+#if HAVE_VIRNETWORKISPERSISTENT
+    rb_define_method(c_network, "persistent?", libvirt_netw_persistent_p, 0);
+#endif
+#endif
+}
diff --git a/ext/libvirt/network.h b/ext/libvirt/network.h
new file mode 100644
index 0000000..1d2c07b
--- /dev/null
+++ b/ext/libvirt/network.h
@@ -0,0 +1,7 @@
+#ifndef NETWORK_H
+#define NETWORK_H
+
+VALUE network_new(virNetworkPtr n, VALUE conn);
+void init_network();
+
+#endif
diff --git a/ext/libvirt/nodedevice.c b/ext/libvirt/nodedevice.c
new file mode 100644
index 0000000..22b2ff4
--- /dev/null
+++ b/ext/libvirt/nodedevice.c
@@ -0,0 +1,220 @@
+/*
+ * nodedevice.c: virNodeDevice methods
+ *
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+
+#if HAVE_TYPE_VIRNODEDEVICEPTR
+static VALUE c_nodedevice;
+
+static void nodedevice_free(void *s) {
+    generic_free(NodeDevice, s);
+}
+
+static virNodeDevicePtr nodedevice_get(VALUE s) {
+    generic_get(NodeDevice, s);
+}
+
+VALUE nodedevice_new(virNodeDevicePtr s, VALUE conn) {
+    return generic_new(c_nodedevice, s, conn, nodedevice_free);
+}
+
+/*
+ * call-seq:
+ *   nodedevice.name -> string
+ *
+ * Call +virNodeDeviceGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceGetName]
+ * to retrieve the name of the node device.
+ */
+static VALUE libvirt_nodedevice_name(VALUE c) {
+    gen_call_string(virNodeDeviceGetName, conn(c), 0, nodedevice_get(c));
+}
+
+/*
+ * call-seq:
+ *   nodedevice.parent -> string
+ *
+ * Call +virNodeDeviceGetParent+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceGetParent]
+ * to retrieve the parent of the node device.
+ */
+static VALUE libvirt_nodedevice_parent(VALUE c) {
+    /* unfortunately we can't use gen_call_string() here because
+     * virNodeDeviceGetParent() returns NULL as a valid value (when this
+     * device has no parent.  Hand-code it instead
+     */
+
+    const char *str;
+
+    str = virNodeDeviceGetParent(nodedevice_get(c));
+    if (str == NULL)
+        return Qnil;
+    else
+        return rb_str_new2(str);
+}
+
+/*
+ * call-seq:
+ *   nodedevice.num_of_caps -> fixnum
+ *
+ * Call +virNodeDeviceNumOfCaps+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceNumOfCaps]
+ * to retrieve the number of capabilities of the node device.
+ */
+static VALUE libvirt_nodedevice_num_of_caps(VALUE c) {
+    gen_call_int(virNodeDeviceNumOfCaps, conn(c), nodedevice_get(c));
+}
+
+/*
+ * call-seq:
+ *   nodedevice.list_caps -> list
+ *
+ * Call +virNodeDeviceListCaps+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceListCaps]
+ * to retrieve a list of capabilities of the node device.
+ */
+static VALUE libvirt_nodedevice_list_caps(VALUE c) {
+    int r, num;
+    virConnectPtr conn = connect_get(c);
+    virNodeDevicePtr nodedev = nodedevice_get(c);
+    char **names;
+
+    num = virNodeDeviceNumOfCaps(nodedev);
+    _E(num < 0, create_error(e_RetrieveError, "virNodeDeviceNumOfCaps", conn));
+    if (num == 0)
+        /* if num is 0, don't call virNodeDeviceListCaps function */
+        return rb_ary_new2(num);
+
+    names = ALLOC_N(char *, num);
+    r = virNodeDeviceListCaps(nodedev, names, num);
+    if (r < 0) {
+        xfree(names);
+        rb_exc_raise(create_error(e_RetrieveError, "virNodeDeviceListCaps",
+                                  conn));
+    }
+
+    return gen_list(num, &names);
+}
+
+/*
+ * call-seq:
+ *   nodedevice.xml_desc(flags=0) -> string
+ *
+ * Call +virNodeDeviceGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceGetXMLDesc]
+ * to retrieve the XML for the node device.
+ */
+static VALUE libvirt_nodedevice_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virNodeDeviceGetXMLDesc, conn(s), 1,
+                    nodedevice_get(s), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   nodedevice.detach -> nil
+ *
+ * Call +virNodeDeviceDettach+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceDettach]
+ * to detach the node device from the node.
+ */
+static VALUE libvirt_nodedevice_detach(VALUE s) {
+    gen_call_void(virNodeDeviceDettach, conn(s), nodedevice_get(s));
+}
+
+/*
+ * call-seq:
+ *   nodedevice.reattach -> nil
+ *
+ * Call +virNodeDeviceReAttach+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceReAttach]
+ * to reattach the node device to the node.
+ */
+static VALUE libvirt_nodedevice_reattach(VALUE s) {
+    gen_call_void(virNodeDeviceReAttach, conn(s), nodedevice_get(s));
+}
+
+/*
+ * call-seq:
+ *   nodedevice.reset -> nil
+ *
+ * Call +virNodeDeviceReset+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceReset]
+ * to reset the node device.
+ */
+static VALUE libvirt_nodedevice_reset(VALUE s) {
+    gen_call_void(virNodeDeviceReset, conn(s), nodedevice_get(s));
+}
+
+#if HAVE_VIRNODEDEVICEDESTROY
+/*
+ * call-seq:
+ *   nodedevice.destroy -> nil
+ *
+ * Call +virNodeDeviceDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceDestroy]
+ * to shutdown the node device.
+ */
+static VALUE libvirt_nodedevice_destroy(VALUE s) {
+    gen_call_void(virNodeDeviceDestroy, conn(s), nodedevice_get(s));
+}
+#endif
+
+/*
+ * call-seq:
+ *   nodedevice.free -> nil
+ *
+ * Call +virNodeDeviceFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virNodeDeviceFree]
+ * to free the node device object.  After this call the node device object is
+ * no longer valid.
+ */
+static VALUE libvirt_nodedevice_free(VALUE s) {
+    gen_call_free(NodeDevice, s);
+}
+#endif
+
+/*
+ * Class Libvirt::NodeDevice
+ */
+void init_nodedevice()
+{
+#if HAVE_TYPE_VIRNODEDEVICEPTR
+    c_nodedevice = rb_define_class_under(m_libvirt, "NodeDevice", rb_cObject);
+
+    rb_define_attr(c_nodedevice, "connection", 1, 0);
+
+    rb_define_method(c_nodedevice, "name", libvirt_nodedevice_name, 0);
+    rb_define_method(c_nodedevice, "parent", libvirt_nodedevice_parent, 0);
+    rb_define_method(c_nodedevice, "num_of_caps",
+                     libvirt_nodedevice_num_of_caps, 0);
+    rb_define_method(c_nodedevice, "list_caps",
+                     libvirt_nodedevice_list_caps, 0);
+    rb_define_method(c_nodedevice, "xml_desc", libvirt_nodedevice_xml_desc, -1);
+    rb_define_method(c_nodedevice, "detach", libvirt_nodedevice_detach, 0);
+    rb_define_method(c_nodedevice, "reattach", libvirt_nodedevice_reattach, 0);
+    rb_define_method(c_nodedevice, "reset", libvirt_nodedevice_reset, 0);
+#if HAVE_VIRNODEDEVICEDESTROY
+    rb_define_method(c_nodedevice, "destroy", libvirt_nodedevice_destroy, 0);
+#endif
+    rb_define_method(c_nodedevice, "free", libvirt_nodedevice_free, 0);
+#endif
+}
diff --git a/ext/libvirt/nodedevice.h b/ext/libvirt/nodedevice.h
new file mode 100644
index 0000000..387ff3d
--- /dev/null
+++ b/ext/libvirt/nodedevice.h
@@ -0,0 +1,6 @@
+#ifndef NODEDEVICE_H
+#define NODEDEVICE_H
+
+void init_nodedevice();
+
+#endif
diff --git a/ext/libvirt/nwfilter.c b/ext/libvirt/nwfilter.c
new file mode 100644
index 0000000..4ab2d17
--- /dev/null
+++ b/ext/libvirt/nwfilter.c
@@ -0,0 +1,133 @@
+/*
+ * nwfilter.c: virNWFilter methods
+ *
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+
+#if HAVE_TYPE_VIRNWFILTERPTR
+static VALUE c_nwfilter;
+
+static void nwfilter_free(void *nw) {
+    generic_free(NWFilter, nw);
+}
+
+static virNWFilterPtr nwfilter_get(VALUE nw) {
+    generic_get(NWFilter, nw);
+}
+
+VALUE nwfilter_new(virNWFilterPtr nw, VALUE conn) {
+    return generic_new(c_nwfilter, nw, conn, nwfilter_free);
+}
+
+/*
+ * call-seq:
+ *   nwfilter.undefine -> nil
+ *
+ * Call +virNWFilterUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterUndefine]
+ * to undefine the network filter.
+ */
+static VALUE libvirt_nwfilter_undefine(VALUE s) {
+    gen_call_void(virNWFilterUndefine, conn(s), nwfilter_get(s));
+}
+
+/*
+ * call-seq:
+ *   nwfilter.name -> string
+ *
+ * Call +virNWFilterGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterGetName]
+ * to retrieve the network filter name.
+ */
+static VALUE libvirt_nwfilter_name(VALUE s) {
+    gen_call_string(virNWFilterGetName, conn(s), 0, nwfilter_get(s));
+}
+
+/*
+ * call-seq:
+ *   nwfilter.uuid -> string
+ *
+ * Call +virNWFilterGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterGetUUIDString]
+ * to retrieve the network filter UUID.
+ */
+static VALUE libvirt_nwfilter_uuid(VALUE s) {
+    virNWFilterPtr nwfilter = nwfilter_get(s);
+    int r;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+
+    r = virNWFilterGetUUIDString(nwfilter, uuid);
+    _E(r < 0, create_error(e_RetrieveError, "virNWFilterGetUUIDString",
+                           conn(s)));
+
+    return rb_str_new2((char *)uuid);
+}
+
+/*
+ * call-seq:
+ *   nwfilter.xml_desc(flags=0) -> string
+ *
+ * Call +virNWFilterGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterGetXMLDesc]
+ * to retrieve the XML for this network filter.
+ */
+static VALUE libvirt_nwfilter_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virNWFilterGetXMLDesc, conn(s), 1, nwfilter_get(s),
+                    NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   nwfilter.free -> nil
+ *
+ * Call +virNWFilterFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virNWFilterFree]
+ * to free this network filter.  After this call the network filter object is
+ * no longer valid.
+ */
+static VALUE libvirt_nwfilter_free(VALUE s) {
+    gen_call_free(NWFilter, s);
+}
+
+#endif
+
+/*
+ * Class Libvirt::NWFilter
+ */
+void init_nwfilter()
+{
+#if HAVE_TYPE_VIRNWFILTERPTR
+    c_nwfilter = rb_define_class_under(m_libvirt, "NWFilter", rb_cObject);
+    rb_define_attr(c_nwfilter, "connection", 1, 0);
+
+    /* NWFilter object methods */
+    rb_define_method(c_nwfilter, "undefine", libvirt_nwfilter_undefine, 0);
+    rb_define_method(c_nwfilter, "name", libvirt_nwfilter_name, 0);
+    rb_define_method(c_nwfilter, "uuid", libvirt_nwfilter_uuid, 0);
+    rb_define_method(c_nwfilter, "xml_desc", libvirt_nwfilter_xml_desc, -1);
+    rb_define_method(c_nwfilter, "free", libvirt_nwfilter_free, 0);
+#endif
+}
diff --git a/ext/libvirt/nwfilter.h b/ext/libvirt/nwfilter.h
new file mode 100644
index 0000000..fc4bc0c
--- /dev/null
+++ b/ext/libvirt/nwfilter.h
@@ -0,0 +1,6 @@
+#ifndef NWFILTER_H
+#define NWFILTER_H
+
+void init_nwfilter();
+
+#endif
diff --git a/ext/libvirt/secret.c b/ext/libvirt/secret.c
new file mode 100644
index 0000000..e62c335
--- /dev/null
+++ b/ext/libvirt/secret.c
@@ -0,0 +1,210 @@
+/*
+ * secret.c: virSecret methods
+ *
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+
+#if HAVE_TYPE_VIRSECRETPTR
+static VALUE c_secret;
+
+static void secret_free(void *s) {
+    generic_free(Secret, s);
+}
+
+static virSecretPtr secret_get(VALUE s) {
+    generic_get(Secret, s);
+}
+
+VALUE secret_new(virSecretPtr s, VALUE conn) {
+    return generic_new(c_secret, s, conn, secret_free);
+}
+
+/*
+ * call-seq:
+ *   secret.uuid -> string
+ *
+ * Call +virSecretGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretGetUUIDString]
+ * to retrieve the UUID for this secret.
+ */
+static VALUE libvirt_secret_uuid(VALUE s) {
+    virSecretPtr secret = secret_get(s);
+    int r;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+
+    r = virSecretGetUUIDString(secret, uuid);
+    _E(r < 0, create_error(e_RetrieveError, "virSecretGetUUIDString", conn(s)));
+
+    return rb_str_new2((char *)uuid);
+}
+
+/*
+ * call-seq:
+ *   secret.usagetype -> fixnum
+ *
+ * Call +virSecretGetUsageType+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretGetUsageType]
+ * to retrieve the usagetype for this secret.
+ */
+static VALUE libvirt_secret_usagetype(VALUE s) {
+    gen_call_int(virSecretGetUsageType, conn(s), secret_get(s));
+}
+
+/*
+ * call-seq:
+ *   secret.usageid -> string
+ *
+ * Call +virSecretGetUsageID+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretGetUsageID]
+ * to retrieve the usageid for this secret.
+ */
+static VALUE libvirt_secret_usageid(VALUE s) {
+    gen_call_string(virSecretGetUsageID, conn(s), 0, secret_get(s));
+}
+
+/*
+ * call-seq:
+ *   secret.xml_desc(flags=0) -> string
+ *
+ * Call +virSecretGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretGetXMLDesc]
+ * to retrieve the XML for this secret.
+ */
+static VALUE libvirt_secret_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virSecretGetXMLDesc, conn(s), 1, secret_get(s),
+                    NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   secret.set_value(value, flags=0) -> nil
+ *
+ * Call +virSecretSetValue+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretSetValue]
+ * to set a new value in this secret.
+ */
+static VALUE libvirt_secret_set_value(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+    VALUE value;
+
+    rb_scan_args(argc, argv, "11", &value, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    StringValue(value);
+
+    gen_call_void(virSecretSetValue, conn(s), secret_get(s),
+                  (unsigned char *)RSTRING_PTR(value), RSTRING_LEN(value),
+                  NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   secret.get_value(flags=0) -> string
+ *
+ * Call +virSecretGetValue+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretGetValue]
+ * to retrieve the value from this secret.
+ */
+static VALUE libvirt_secret_get_value(int argc, VALUE *argv, VALUE s) {
+    virSecretPtr secret = secret_get(s);
+    VALUE flags;
+    unsigned char *val;
+    size_t value_size;
+    VALUE ret;
+    int exception = 0;
+    struct rb_str_new_arg args;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    val = virSecretGetValue(secret, &value_size, NUM2UINT(flags));
+
+    _E(val == NULL, create_error(e_RetrieveError, "virSecretGetValue",
+                                 conn(s)));
+
+    args.val = (char *)val;
+    args.size = value_size;
+    ret = rb_protect(rb_str_new_wrap, (VALUE)&args, &exception);
+    if (exception) {
+        free(val);
+        rb_jump_tag(exception);
+    }
+
+    free(val);
+
+    return ret;
+}
+
+/*
+ * call-seq:
+ *   secret.undefine -> nil
+ *
+ * Call +virSecretUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretUndefine]
+ * to undefine this secret.
+ */
+static VALUE libvirt_secret_undefine(VALUE s) {
+    gen_call_void(virSecretUndefine, conn(s), secret_get(s));
+}
+
+/*
+ * call-seq:
+ *   secret.free -> nil
+ *
+ * Call +virSecretFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virSecretFree]
+ * to free this secret.  After this call the secret object is no longer valid.
+ */
+static VALUE libvirt_secret_free(VALUE s) {
+    gen_call_free(Secret, s);
+}
+
+#endif
+
+/*
+ * Class Libvirt::Secret
+ */
+void init_secret()
+{
+#if HAVE_TYPE_VIRSECRETPTR
+    c_secret = rb_define_class_under(m_libvirt, "Secret", rb_cObject);
+
+    rb_define_const(c_secret, "USAGE_TYPE_VOLUME",
+                    INT2NUM(VIR_SECRET_USAGE_TYPE_VOLUME));
+    rb_define_attr(c_secret, "connection", 1, 0);
+
+    /* Secret object methods */
+    rb_define_method(c_secret, "uuid", libvirt_secret_uuid, 0);
+    rb_define_method(c_secret, "usagetype", libvirt_secret_usagetype, 0);
+    rb_define_method(c_secret, "usageid", libvirt_secret_usageid, 0);
+    rb_define_method(c_secret, "xml_desc", libvirt_secret_xml_desc, -1);
+    rb_define_method(c_secret, "set_value", libvirt_secret_set_value, -1);
+    rb_define_method(c_secret, "get_value", libvirt_secret_get_value, -1);
+    rb_define_method(c_secret, "undefine", libvirt_secret_undefine, 0);
+    rb_define_method(c_secret, "free", libvirt_secret_free, 0);
+#endif
+}
diff --git a/ext/libvirt/secret.h b/ext/libvirt/secret.h
new file mode 100644
index 0000000..e2bce35
--- /dev/null
+++ b/ext/libvirt/secret.h
@@ -0,0 +1,6 @@
+#ifndef SECRET_H
+#define SECRET_H
+
+void init_secret();
+
+#endif
diff --git a/ext/libvirt/storage.c b/ext/libvirt/storage.c
new file mode 100644
index 0000000..f3c8487
--- /dev/null
+++ b/ext/libvirt/storage.c
@@ -0,0 +1,776 @@
+/*
+ * storage.c: virStoragePool and virStorageVolume methods
+ *
+ * Copyright (C) 2007,2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+#include "stream.h"
+
+#if HAVE_TYPE_VIRSTORAGEVOLPTR
+/* this has to be here (as opposed to below with the rest of the volume
+ * stuff) because libvirt_vol_get_pool() relies on it
+ */
+static virStorageVolPtr vol_get(VALUE s) {
+    generic_get(StorageVol, s);
+}
+#endif
+
+#if HAVE_TYPE_VIRSTORAGEPOOLPTR
+static VALUE c_storage_pool;
+static VALUE c_storage_pool_info;
+
+/*
+ * Class Libvirt::StoragePool
+ */
+
+static void pool_free(void *d) {
+    generic_free(StoragePool, d);
+}
+
+static virStoragePoolPtr pool_get(VALUE s) {
+    generic_get(StoragePool, s);
+}
+
+VALUE pool_new(virStoragePoolPtr n, VALUE conn) {
+    return generic_new(c_storage_pool, n, conn, pool_free);
+}
+
+/*
+ * call-seq:
+ *   vol.pool -> Libvirt::StoragePool
+ *
+ * Call +virStoragePoolLookupByVolume+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolLookupByVolume]
+ * to retrieve the storage pool for this volume.
+ */
+static VALUE libvirt_vol_get_pool(VALUE v) {
+    virStoragePoolPtr pool;
+
+    pool = virStoragePoolLookupByVolume(vol_get(v));
+    _E(pool == NULL, create_error(e_RetrieveError,
+                                  "virStoragePoolLookupByVolume", conn(v)));
+
+    return pool_new(pool, conn_attr(v));
+}
+
+/*
+ * call-seq:
+ *   pool.build(flags=0) -> nil
+ *
+ * Call +virStoragePoolBuild+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolBuild]
+ * to build this storage pool.
+ */
+static VALUE libvirt_pool_build(int argc, VALUE *argv, VALUE p) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStoragePoolBuild, conn(p), pool_get(p), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   pool.undefine -> nil
+ *
+ * Call +virStoragePoolUndefine+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolUndefine]
+ * to undefine this storage pool.
+ */
+static VALUE libvirt_pool_undefine(VALUE p) {
+    gen_call_void(virStoragePoolUndefine, conn(p), pool_get(p));
+}
+
+/*
+ * call-seq:
+ *   pool.create(flags=0) -> nil
+ *
+ * Call +virStoragePoolCreate+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolCreate]
+ * to start this storage pool.
+ */
+static VALUE libvirt_pool_create(int argc, VALUE *argv, VALUE p) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStoragePoolCreate, conn(p), pool_get(p), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   pool.destroy -> nil
+ *
+ * Call +virStoragePoolDestroy+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolDestroy]
+ * to shutdown this storage pool.
+ */
+static VALUE libvirt_pool_destroy(VALUE p) {
+    gen_call_void(virStoragePoolDestroy, conn(p), pool_get(p));
+}
+
+/*
+ * call-seq:
+ *   pool.delete(flags=0) -> nil
+ *
+ * Call +virStoragePoolDelete+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolDelete]
+ * to delete the data corresponding to this data pool.  This is a destructive
+ * operation.
+ */
+static VALUE libvirt_pool_delete(int argc, VALUE *argv, VALUE p) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStoragePoolDelete, conn(p), pool_get(p), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   pool.refresh(flags=0) -> nil
+ *
+ * Call +virStoragePoolRefresh+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolRefresh]
+ * to refresh the list of volumes in this storage pool.
+ */
+static VALUE libvirt_pool_refresh(int argc, VALUE *argv, VALUE p) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStoragePoolRefresh, conn(p), pool_get(p), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   pool.name -> string
+ *
+ * Call +virStoragePoolGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetName]
+ * to retrieve the name of this storage pool.
+ */
+static VALUE libvirt_pool_name(VALUE s) {
+    gen_call_string(virStoragePoolGetName, conn(s), 0, pool_get(s));
+}
+
+/*
+ * call-seq:
+ *   pool.uuid -> string
+ *
+ * Call +virStoragePoolGetUUIDString+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetUUIDString]
+ * to retrieve the UUID of this storage pool.
+ */
+static VALUE libvirt_pool_uuid(VALUE s) {
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    int r;
+
+    r = virStoragePoolGetUUIDString(pool_get(s), uuid);
+    _E(r < 0, create_error(e_RetrieveError, "virStoragePoolGetUUIDString",
+                           conn(s)));
+
+    return rb_str_new2((char *) uuid);
+}
+
+/*
+ * call-seq:
+ *   pool.info -> Libvirt::StoragePoolInfo
+ *
+ * Call +virStoragePoolGetInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetInfo]
+ * to retrieve information about this storage pool.
+ */
+static VALUE libvirt_pool_info(VALUE s) {
+    virStoragePoolInfo info;
+    int r;
+    VALUE result;
+
+    r = virStoragePoolGetInfo(pool_get(s), &info);
+    _E(r < 0, create_error(e_RetrieveError, "virStoragePoolGetInfo", conn(s)));
+
+    result = rb_class_new_instance(0, NULL, c_storage_pool_info);
+    rb_iv_set(result, "@state", INT2NUM(info.state));
+    rb_iv_set(result, "@capacity", ULL2NUM(info.capacity));
+    rb_iv_set(result, "@allocation", ULL2NUM(info.allocation));
+    rb_iv_set(result, "@available", ULL2NUM(info.available));
+
+    return result;
+}
+
+/*
+ * call-seq:
+ *   pool.xml_desc(flags=0) -> string
+ *
+ * Call +virStoragePoolGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetXMLDesc]
+ * to retrieve the XML for this storage pool.
+ */
+static VALUE libvirt_pool_xml_desc(int argc, VALUE *argv, VALUE s) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virStoragePoolGetXMLDesc, conn(s), 1, pool_get(s),
+                    NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   pool.autostart? -> [true|false]
+ *
+ * Call +virStoragePoolGetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolGetAutostart]
+ * to determine whether this storage pool will autostart when libvirtd starts.
+ */
+static VALUE libvirt_pool_autostart(VALUE s){
+    int r, autostart;
+
+    r = virStoragePoolGetAutostart(pool_get(s), &autostart);
+    _E(r < 0, create_error(e_RetrieveError, "virStoragePoolGetAutostart",
+                           conn(s)));
+
+    return autostart ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   pool.autostart = [true|false]
+ *
+ * Call +virStoragePoolSetAutostart+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolSetAutostart]
+ * to make this storage pool start when libvirtd starts.
+ */
+static VALUE libvirt_pool_autostart_set(VALUE s, VALUE autostart) {
+    if (autostart != Qtrue && autostart != Qfalse)
+		rb_raise(rb_eTypeError,
+                 "wrong argument type (expected TrueClass or FalseClass)");
+
+    gen_call_void(virStoragePoolSetAutostart, conn(s), pool_get(s),
+                  RTEST(autostart) ? 1 : 0);
+}
+
+/*
+ * call-seq:
+ *   pool.num_of_volumes -> fixnum
+ *
+ * Call +virStoragePoolNumOfVolumes+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolNumOfVolumes]
+ * to retrieve the number of volumes in this storage pool.
+ */
+static VALUE libvirt_pool_num_of_volumes(VALUE s) {
+    int n = virStoragePoolNumOfVolumes(pool_get(s));
+    _E(n < 0, create_error(e_RetrieveError, "virStoragePoolNumOfVolumes",
+                           conn(s)));
+
+    return INT2NUM(n);
+}
+
+/*
+ * call-seq:
+ *   pool.list_volumes -> list
+ *
+ * Call +virStoragePoolListVolumes+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolListVolumes]
+ * to retrieve a list of volume names in this storage pools.
+ */
+static VALUE libvirt_pool_list_volumes(VALUE s) {
+    int r, num;
+    char **names;
+    virStoragePoolPtr pool = pool_get(s);
+
+    num = virStoragePoolNumOfVolumes(pool);
+    _E(num < 0, create_error(e_RetrieveError, "virStoragePoolNumOfVolumes",
+                             conn(s)));
+    if (num == 0)
+        return rb_ary_new2(num);
+
+    names = ALLOC_N(char *, num);
+    r = virStoragePoolListVolumes(pool, names, num);
+    if (r < 0) {
+        xfree(names);
+        rb_exc_raise(create_error(e_RetrieveError, "virStoragePoolListVolumes",
+                                  conn(s)));
+    }
+
+    return gen_list(num, &names);
+}
+
+/*
+ * call-seq:
+ *   pool.free -> nil
+ *
+ * Call +virStoragePoolFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolFree]
+ * to free this storage pool object.  After this call the storage pool object
+ * is no longer valid.
+ */
+static VALUE libvirt_pool_free(VALUE s) {
+    gen_call_free(StoragePool, s);
+}
+#endif
+
+#if HAVE_TYPE_VIRSTORAGEVOLPTR
+/*
+ * Libvirt::StorageVol
+ */
+static VALUE c_storage_vol;
+static VALUE c_storage_vol_info;
+
+static void vol_free(void *d) {
+    generic_free(StorageVol, d);
+}
+
+static VALUE vol_new(virStorageVolPtr n, VALUE conn) {
+    return generic_new(c_storage_vol, n, conn, vol_free);
+}
+
+/*
+ * call-seq:
+ *   pool.lookup_volume_by_name(name) -> Libvirt::StorageVol
+ *
+ * Call +virStorageVolLookupByName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByName]
+ * to retrieve a storage volume object by name.
+ */
+static VALUE libvirt_pool_lookup_vol_by_name(VALUE p, VALUE name) {
+    virStorageVolPtr vol;
+
+    vol = virStorageVolLookupByName(pool_get(p), StringValueCStr(name));
+    _E(vol == NULL, create_error(e_RetrieveError, "virStorageVolLookupByName",
+                                 conn(p)));
+
+    return vol_new(vol, conn_attr(p));
+}
+
+/*
+ * call-seq:
+ *   pool.lookup_volume_by_key(key) -> Libvirt::StorageVol
+ *
+ * Call +virStorageVolLookupByKey+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByKey]
+ * to retrieve a storage volume object by key.
+ */
+static VALUE libvirt_pool_lookup_vol_by_key(VALUE p, VALUE key) {
+    virStorageVolPtr vol;
+
+    /* FIXME: Why does this take a connection, not a pool? */
+    vol = virStorageVolLookupByKey(conn(p), StringValueCStr(key));
+    _E(vol == NULL, create_error(e_RetrieveError, "virStorageVolLookupByKey",
+                                 conn(p)));
+
+    return vol_new(vol, conn_attr(p));
+}
+
+/*
+ * call-seq:
+ *   pool.lookup_volume_by_path(path) -> Libvirt::StorageVol
+ *
+ * Call +virStorageVolLookupByPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByPath]
+ * to retrieve a storage volume object by path.
+ */
+static VALUE libvirt_pool_lookup_vol_by_path(VALUE p, VALUE path) {
+    virStorageVolPtr vol;
+
+    /* FIXME: Why does this take a connection, not a pool? */
+    vol = virStorageVolLookupByPath(conn(p), StringValueCStr(path));
+    _E(vol == NULL, create_error(e_RetrieveError, "virStorageVolLookupByPath",
+                                 conn(p)));
+
+    return vol_new(vol, conn_attr(p));
+}
+
+/*
+ * call-seq:
+ *   vol.name -> string
+ *
+ * Call +virStorageVolGetName+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetName]
+ * to retrieve the name of this storage volume.
+ */
+static VALUE libvirt_vol_name(VALUE v) {
+    gen_call_string(virStorageVolGetName, conn(v), 0, vol_get(v));
+}
+
+/*
+ * call-seq:
+ *   vol.key -> string
+ *
+ * Call +virStorageVolGetKey+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetKey]
+ * to retrieve the key for this storage volume.
+ */
+static VALUE libvirt_vol_key(VALUE v) {
+    gen_call_string(virStorageVolGetKey, conn(v), 0, vol_get(v));
+}
+
+/*
+ * call-seq:
+ *   pool.create_volume_xml(xml, flags=0) -> Libvirt::StorageVol
+ *
+ * Call +virStorageVolCreateXML+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolCreateXML]
+ * to create a new storage volume from xml.
+ */
+static VALUE libvirt_pool_vol_create_xml(int argc, VALUE *argv, VALUE p) {
+    virStorageVolPtr vol;
+    virConnectPtr c = conn(p);
+    VALUE xml, flags;
+
+    rb_scan_args(argc, argv, "11", &xml, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    vol = virStorageVolCreateXML(pool_get(p), StringValueCStr(xml),
+                                 NUM2UINT(flags));
+    _E(vol == NULL, create_error(e_Error, "virNetworkCreateXML", c));
+
+    return vol_new(vol, conn_attr(p));
+}
+
+#if HAVE_VIRSTORAGEVOLCREATEXMLFROM
+/*
+ * call-seq:
+ *   pool.create_volume_xml_from(xml, clonevol, flags=0) -> Libvirt::StorageVol
+ *
+ * Call +virStorageVolCreateXMLFrom+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolCreateXMLFrom]
+ * to clone a volume from an existing volume with the properties specified in
+ * xml.
+ */
+static VALUE libvirt_pool_vol_create_xml_from(int argc, VALUE *argv, VALUE p) {
+    virStorageVolPtr vol;
+    virConnectPtr c = conn(p);
+    VALUE xml, flags, cloneval;
+
+    rb_scan_args(argc, argv, "21", &xml, &cloneval, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    vol = virStorageVolCreateXMLFrom(pool_get(p), StringValueCStr(xml),
+                                     vol_get(cloneval), NUM2UINT(flags));
+    _E(vol == NULL, create_error(e_Error, "virNetworkCreateXMLFrom", c));
+
+    return vol_new(vol, conn_attr(p));
+}
+#endif
+
+#if HAVE_VIRSTORAGEPOOLISACTIVE
+/*
+ * call-seq:
+ *   pool.active? -> [true|false]
+ *
+ * Call +virStoragePoolIsActive+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolIsActive]
+ * to determine if this storage pool is active.
+ */
+static VALUE libvirt_pool_active_p(VALUE p) {
+    gen_call_truefalse(virStoragePoolIsActive, conn(p), pool_get(p));
+}
+#endif
+
+#if HAVE_VIRSTORAGEPOOLISPERSISTENT
+/*
+ * call-seq:
+ *   pool.persistent? -> [true|false]
+ *
+ * Call +virStoragePoolIsPersistent+[http://www.libvirt.org/html/libvirt-libvirt.html#virStoragePoolIsPersistent]
+ * to determine if this storage pool is persistent.
+ */
+static VALUE libvirt_pool_persistent_p(VALUE p) {
+    gen_call_truefalse(virStoragePoolIsPersistent, conn(p), pool_get(p));
+}
+#endif
+
+/*
+ * call-seq:
+ *   vol.delete(flags=0) -> nil
+ *
+ * Call +virStorageVolDelete+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolDelete]
+ * to delete this volume.  This is a destructive operation.
+ */
+static VALUE libvirt_vol_delete(int argc, VALUE *argv, VALUE v) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStorageVolDelete, conn(v), vol_get(v), NUM2UINT(flags));
+}
+
+#if HAVE_VIRSTORAGEVOLWIPE
+/*
+ * call-seq:
+ *   vol.wipe(flags=0) -> nil
+ *
+ * Call +virStorageVolWipe+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolWipe]
+ * to wipe the data from this storage volume.  This is a destructive operation.
+ */
+static VALUE libvirt_vol_wipe(int argc, VALUE *argv, VALUE v) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStorageVolWipe, conn(v), vol_get(v), NUM2UINT(flags));
+}
+#endif
+
+/*
+ * call-seq:
+ *   vol.info -> Libvirt::StorageVolInfo
+ *
+ * Call +virStorageVolGetInfo+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetInfo]
+ * to retrieve information about this storage volume.
+ */
+static VALUE libvirt_vol_info(VALUE v) {
+    virStorageVolInfo info;
+    int r;
+    VALUE result;
+
+    r = virStorageVolGetInfo(vol_get(v), &info);
+    _E(r < 0, create_error(e_RetrieveError, "virStorageVolGetInfo", conn(v)));
+
+    result = rb_class_new_instance(0, NULL, c_storage_vol_info);
+    rb_iv_set(result, "@type", INT2NUM(info.type));
+    rb_iv_set(result, "@capacity", ULL2NUM(info.capacity));
+    rb_iv_set(result, "@allocation", ULL2NUM(info.allocation));
+
+    return result;
+}
+
+/*
+ * call-seq:
+ *   vol.xml_desc(flags=0) -> string
+ *
+ * Call +virStorageVolGetXMLDesc+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetXMLDesc]
+ * to retrieve the xml for this storage volume.
+ */
+static VALUE libvirt_vol_xml_desc(int argc, VALUE *argv, VALUE v) {
+    VALUE flags;
+
+    rb_scan_args(argc, argv, "01", &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_string(virStorageVolGetXMLDesc, conn(v), 1, vol_get(v),
+                    NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   vol.path -> string
+ *
+ * Call +virStorageVolGetPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolGetPath]
+ * to retrieve the path for this storage volume.
+ */
+static VALUE libvirt_vol_path(VALUE v) {
+    gen_call_string(virStorageVolGetPath, conn(v), 1, vol_get(v));
+}
+
+/*
+ * call-seq:
+ *   vol.free -> nil
+ *
+ * Call +virStorageVolFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolFree]
+ * to free the storage volume object.  After this call the storage volume object
+ * is no longer valid.
+ */
+static VALUE libvirt_vol_free(VALUE s) {
+    gen_call_free(StorageVol, s);
+}
+#endif
+
+#if HAVE_VIRSTORAGEVOLDOWNLOAD
+/*
+ * call-seq:
+ *   vol.download(stream, offset, length, flags=0) -> nil
+ *
+ * Call +virStorageVolDownload+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolDownload]
+ * to download the content of a volume as a stream.
+ */
+static VALUE libvirt_vol_download(int argc, VALUE *argv, VALUE v) {
+    VALUE st, offset, length, flags;
+
+    rb_scan_args(argc, argv, "31", &st, &offset, &length, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStorageVolDownload, conn(v), vol_get(v), stream_get(st),
+                  NUM2ULL(offset), NUM2ULL(length), NUM2UINT(flags));
+}
+
+/*
+ * call-seq:
+ *   vol.upload(stream, offset, length, flags=0) -> nil
+ *
+ * Call +virStorageVolUpload+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolUpload]
+ * to upload new content to a volume from a stream.
+ */
+static VALUE libvirt_vol_upload(int argc, VALUE *argv, VALUE v) {
+    VALUE st, offset, length, flags;
+
+    rb_scan_args(argc, argv, "31", &st, &offset, &length, &flags);
+
+    if (NIL_P(flags))
+        flags = INT2NUM(0);
+
+    gen_call_void(virStorageVolUpload, conn(v), vol_get(v), stream_get(st),
+                  NUM2ULL(offset), NUM2ULL(length), NUM2UINT(flags));
+}
+#endif
+
+void init_storage(void) {
+    /*
+     * Class Libvirt::StoragePool and Libvirt::StoragePoolInfo
+     */
+#if HAVE_TYPE_VIRSTORAGEPOOLPTR
+    c_storage_pool_info = rb_define_class_under(m_libvirt, "StoragePoolInfo",
+                                                rb_cObject);
+    rb_define_attr(c_storage_pool_info, "state", 1, 0);
+    rb_define_attr(c_storage_pool_info, "capacity", 1, 0);
+    rb_define_attr(c_storage_pool_info, "allocation", 1, 0);
+    rb_define_attr(c_storage_pool_info, "available", 1, 0);
+
+    c_storage_pool = rb_define_class_under(m_libvirt, "StoragePool",
+                                           rb_cObject);
+
+    rb_define_attr(c_storage_pool, "connection", 1, 0);
+
+    /* virStoragePoolState */
+    rb_define_const(c_storage_pool, "INACTIVE",
+                    INT2NUM(VIR_STORAGE_POOL_INACTIVE));
+    rb_define_const(c_storage_pool, "BUILDING",
+                    INT2NUM(VIR_STORAGE_POOL_BUILDING));
+    rb_define_const(c_storage_pool, "RUNNING",
+                    INT2NUM(VIR_STORAGE_POOL_RUNNING));
+    rb_define_const(c_storage_pool, "DEGRADED",
+                    INT2NUM(VIR_STORAGE_POOL_DEGRADED));
+#if HAVE_CONST_VIR_STORAGE_POOL_INACCESSIBLE
+    rb_define_const(c_storage_pool, "INACCESSIBLE",
+                    INT2NUM(VIR_STORAGE_POOL_INACCESSIBLE));
+#endif
+
+    /* virStoragePoolBuildFlags */
+    rb_define_const(c_storage_pool, "BUILD_NEW",
+                    INT2NUM(VIR_STORAGE_POOL_BUILD_NEW));
+    rb_define_const(c_storage_pool, "BUILD_REPAIR",
+                    INT2NUM(VIR_STORAGE_POOL_BUILD_REPAIR));
+    rb_define_const(c_storage_pool, "BUILD_RESIZE",
+                    INT2NUM(VIR_STORAGE_POOL_BUILD_RESIZE));
+
+    /* virStoragePoolDeleteFlags */
+    rb_define_const(c_storage_pool, "DELETE_NORMAL",
+                    INT2NUM(VIR_STORAGE_POOL_DELETE_NORMAL));
+    rb_define_const(c_storage_pool, "DELETE_ZEROED",
+                    INT2NUM(VIR_STORAGE_POOL_DELETE_ZEROED));
+
+    /* Creating/destroying pools */
+    rb_define_method(c_storage_pool, "build", libvirt_pool_build, -1);
+    rb_define_method(c_storage_pool, "undefine", libvirt_pool_undefine, 0);
+    rb_define_method(c_storage_pool, "create", libvirt_pool_create, -1);
+    rb_define_method(c_storage_pool, "destroy", libvirt_pool_destroy, 0);
+    rb_define_method(c_storage_pool, "delete", libvirt_pool_delete, -1);
+    rb_define_method(c_storage_pool, "refresh", libvirt_pool_refresh, -1);
+    /* StoragePool information */
+    rb_define_method(c_storage_pool, "name", libvirt_pool_name, 0);
+    rb_define_method(c_storage_pool, "uuid", libvirt_pool_uuid, 0);
+    rb_define_method(c_storage_pool, "info", libvirt_pool_info, 0);
+    rb_define_method(c_storage_pool, "xml_desc", libvirt_pool_xml_desc, -1);
+    rb_define_method(c_storage_pool, "autostart", libvirt_pool_autostart, 0);
+    rb_define_method(c_storage_pool, "autostart?", libvirt_pool_autostart, 0);
+    rb_define_method(c_storage_pool, "autostart=",
+                     libvirt_pool_autostart_set, 1);
+    /* List/lookup storage volumes within a pool */
+    rb_define_method(c_storage_pool, "num_of_volumes",
+                     libvirt_pool_num_of_volumes, 0);
+    rb_define_method(c_storage_pool, "list_volumes",
+                     libvirt_pool_list_volumes, 0);
+    /* Lookup volumes based on various attributes */
+    rb_define_method(c_storage_pool, "lookup_volume_by_name",
+                     libvirt_pool_lookup_vol_by_name, 1);
+    rb_define_method(c_storage_pool, "lookup_volume_by_key",
+                     libvirt_pool_lookup_vol_by_key, 1);
+    rb_define_method(c_storage_pool, "lookup_volume_by_path",
+                     libvirt_pool_lookup_vol_by_path, 1);
+    rb_define_method(c_storage_pool, "free", libvirt_pool_free, 0);
+    rb_define_method(c_storage_pool, "create_vol_xml",
+                     libvirt_pool_vol_create_xml, -1);
+    rb_define_alias(c_storage_pool, "create_volume_xml", "create_vol_xml");
+#if HAVE_VIRSTORAGEVOLCREATEXMLFROM
+    rb_define_method(c_storage_pool, "create_vol_xml_from",
+                     libvirt_pool_vol_create_xml_from, -1);
+    rb_define_alias(c_storage_pool, "create_volume_xml_from",
+                    "create_vol_xml_from");
+#endif
+#if HAVE_VIRSTORAGEPOOLISACTIVE
+    rb_define_method(c_storage_pool, "active?", libvirt_pool_active_p, 0);
+#endif
+#if HAVE_VIRSTORAGEPOOLISPERSISTENT
+    rb_define_method(c_storage_pool, "persistent?",
+                     libvirt_pool_persistent_p, 0);
+#endif
+#endif
+
+#if HAVE_TYPE_VIRSTORAGEVOLPTR
+    /*
+     * Class Libvirt::StorageVol and Libvirt::StorageVolInfo
+     */
+    c_storage_vol_info = rb_define_class_under(m_libvirt, "StorageVolInfo",
+                                               rb_cObject);
+    rb_define_attr(c_storage_vol_info, "type", 1, 0);
+    rb_define_attr(c_storage_vol_info, "capacity", 1, 0);
+    rb_define_attr(c_storage_vol_info, "allocation", 1, 0);
+
+    c_storage_vol = rb_define_class_under(m_libvirt, "StorageVol",
+                                          rb_cObject);
+
+    /* virStorageVolType */
+    rb_define_const(c_storage_vol, "FILE", INT2NUM(VIR_STORAGE_VOL_FILE));
+    rb_define_const(c_storage_vol, "BLOCK", INT2NUM(VIR_STORAGE_VOL_BLOCK));
+
+    /* virStorageVolDeleteFlags */
+    rb_define_const(c_storage_vol, "DELETE_NORMAL",
+                    INT2NUM(VIR_STORAGE_VOL_DELETE_NORMAL));
+    rb_define_const(c_storage_vol, "DELETE_ZEROED",
+                    INT2NUM(VIR_STORAGE_VOL_DELETE_ZEROED));
+
+    rb_define_method(c_storage_vol, "pool", libvirt_vol_get_pool, 0);
+    rb_define_method(c_storage_vol, "name", libvirt_vol_name, 0);
+    rb_define_method(c_storage_vol, "key", libvirt_vol_key, 0);
+    rb_define_method(c_storage_vol, "delete", libvirt_vol_delete, -1);
+#if HAVE_VIRSTORAGEVOLWIPE
+    rb_define_method(c_storage_vol, "wipe", libvirt_vol_wipe, -1);
+#endif
+    rb_define_method(c_storage_vol, "info", libvirt_vol_info, 0);
+    rb_define_method(c_storage_vol, "xml_desc", libvirt_vol_xml_desc, -1);
+    rb_define_method(c_storage_vol, "path", libvirt_vol_path, 0);
+    rb_define_method(c_storage_vol, "free", libvirt_vol_free, 0);
+
+#if HAVE_VIRSTORAGEVOLDOWNLOAD
+    rb_define_method(c_storage_vol, "download", libvirt_vol_download, -1);
+    rb_define_method(c_storage_vol, "upload", libvirt_vol_upload, -1);
+#endif
+
+#endif
+}
diff --git a/ext/libvirt/storage.h b/ext/libvirt/storage.h
new file mode 100644
index 0000000..2cfd34a
--- /dev/null
+++ b/ext/libvirt/storage.h
@@ -0,0 +1,6 @@
+#ifndef STORAGE_H
+#define STORAGE_H
+
+void init_storage();
+
+#endif
diff --git a/ext/libvirt/stream.c b/ext/libvirt/stream.c
new file mode 100644
index 0000000..3d120be
--- /dev/null
+++ b/ext/libvirt/stream.c
@@ -0,0 +1,394 @@
+/*
+ * stream.c: virStream methods
+ *
+ * Copyright (C) 2007,2010 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <ruby.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include "common.h"
+#include "connect.h"
+#include "extconf.h"
+
+#if HAVE_TYPE_VIRSTREAMPTR
+static VALUE c_stream;
+
+static void stream_free(void *s) {
+    generic_free(Stream, s);
+}
+
+virStreamPtr stream_get(VALUE s) {
+    generic_get(Stream, s);
+}
+
+VALUE stream_new(virStreamPtr s, VALUE conn) {
+    return generic_new(c_stream, s, conn, stream_free);
+}
+
+/*
+ * call-seq:
+ *   stream.send(buffer) -> Fixnum
+ *
+ * Call +virStreamSend+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamSend]
+ * to send the data in buffer out to the stream.  The return value is the
+ * number of bytes sent, which may be less than the size of the buffer.  If
+ * an error occurred, -1 is returned.  If the transmit buffers are full and the
+ * stream is marked non-blocking, returns -2.
+ */
+static VALUE libvirt_stream_send(VALUE s, VALUE buffer) {
+    int ret;
+
+    StringValue(buffer);
+
+    ret = virStreamSend(stream_get(s), RSTRING_PTR(buffer),
+                        RSTRING_LEN(buffer));
+    _E(ret == -1, create_error(e_RetrieveError, "virStreamSend", conn(s)));
+
+    return INT2NUM(ret);
+}
+
+struct stream_recv_args {
+    int ret;
+    char *data;
+};
+
+static VALUE stream_recv_array(VALUE input) {
+    VALUE result;
+    struct stream_recv_args *args = (struct stream_recv_args *)input;
+
+    result = rb_ary_new();
+
+    rb_ary_push(result, INT2NUM(args->ret));
+    rb_ary_push(result, rb_str_new(args->data, args->ret));
+
+    return result;
+}
+
+/*
+ * call-seq:
+ *   stream.recv(bytes) -> [return_value, data]
+ *
+ * Call +virStreamRecv+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamRecv]
+ * to receive up to bytes amount of data from the stream.  The return is an
+ * array with two elements; the return code from the virStreamRecv call and
+ * the data (as a String) read from the stream.  If an error occurred, the
+ * return_value is set to -1.  If there is no data pending and the stream is
+ * marked as non-blocking, return_value is set to -2.
+ */
+static VALUE libvirt_stream_recv(VALUE s, VALUE bytes) {
+    char *data;
+    int ret;
+    int exception = 0;
+    VALUE result;
+    struct stream_recv_args args;
+
+    data = ALLOC_N(char, NUM2INT(bytes));
+
+    ret = virStreamRecv(stream_get(s), data, NUM2INT(bytes));
+    if (ret == -1) {
+        xfree(data);
+        rb_exc_raise(create_error(e_RetrieveError, "virStreamRecv", conn(s)));
+    }
+
+    args.ret = ret;
+    args.data = data;
+    result = rb_protect(stream_recv_array, (VALUE)&args, &exception);
+    if (exception) {
+        xfree(data);
+        rb_jump_tag(exception);
+    }
+
+    xfree(data);
+    return result;
+}
+
+static int internal_sendall(virStreamPtr st, char *data, size_t nbytes,
+                            void *opaque) {
+    VALUE result;
+    VALUE retcode, buffer;
+
+    result = rb_yield_values(2, (VALUE)opaque, INT2NUM(nbytes));
+
+    if (TYPE(result) != T_ARRAY)
+        rb_raise(rb_eTypeError, "wrong type (expected Array)");
+
+    if (RARRAY_LEN(result) != 2)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)",
+                 RARRAY_LEN(result));
+
+    retcode = rb_ary_entry(result, 0);
+    buffer = rb_ary_entry(result, 1);
+
+    if (NUM2INT(retcode) < 0)
+        return NUM2INT(retcode);
+
+    StringValue(buffer);
+
+    if (RSTRING_LEN(buffer) > nbytes)
+        rb_raise(rb_eArgError, "asked for %d bytes, block returned %d", nbytes,
+                 RSTRING_LEN(buffer));
+
+    memcpy(data, RSTRING_PTR(buffer), RSTRING_LEN(buffer));
+
+    return NUM2INT(retcode);
+}
+
+/*
+ * call-seq:
+ *   stream.sendall(opaque=nil){|opaque, nbytes| send block} -> nil
+ *
+ * Call +virStreamSendAll+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamSendAll]
+ * to send the entire data stream.  The send block is required and is executed
+ * one or more times to send data.  Each invocation of the send block yields
+ * the opaque data passed into the initial call and the number of bytes this
+ * iteration is prepared to handle.  The send block should return an array of
+ * 2 elements; the first element should be the return code from the block
+ * (-1 for error, 0 otherwise), and the second element should be the data
+ * that the block prepared to send.
+ */
+static VALUE libvirt_stream_sendall(int argc, VALUE *argv, VALUE s) {
+    VALUE opaque;
+    int ret;
+
+    if (!rb_block_given_p())
+        rb_raise(rb_eRuntimeError, "A block must be provided");
+
+    rb_scan_args(argc, argv, "01", &opaque);
+
+    ret = virStreamSendAll(stream_get(s), internal_sendall, (void *)opaque);
+    _E(ret < 0, create_error(e_RetrieveError, "virStreamSendAll", conn(s)));
+
+    return Qnil;
+}
+
+static int internal_recvall(virStreamPtr st, const char *buf, size_t nbytes,
+                            void *opaque) {
+    VALUE result;
+
+    result = rb_yield_values(2, rb_str_new(buf, nbytes), (VALUE)opaque);
+
+    if (TYPE(result) != T_FIXNUM)
+        rb_raise(rb_eArgError, "wrong type (expected an integer)");
+
+    return NUM2INT(result);
+}
+
+/*
+ * call-seq:
+ *   stream.recvall(opaque){|data, opaque| receive block} -> nil
+ *
+ * Call +virStreamRecvAll+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamRecvAll]
+ * to receive the entire data stream.  The receive block is required and is
+ * called one or more times to receive data.  Each invocation of the receive
+ * block yields the data received and the opaque data passed into the initial
+ * call.  The block should return -1 if an error occurred and 0 otherwise.
+ */
+static VALUE libvirt_stream_recvall(int argc, VALUE *argv, VALUE s) {
+    VALUE opaque;
+    int ret;
+
+    if (!rb_block_given_p())
+        rb_raise(rb_eRuntimeError, "A block must be provided");
+
+    rb_scan_args(argc, argv, "01", &opaque);
+
+    ret = virStreamRecvAll(stream_get(s), internal_recvall, (void *)opaque);
+    _E(ret < 0, create_error(e_RetrieveError, "virStreamRecvAll", conn(s)));
+
+    return Qnil;
+}
+
+static void stream_event_callback(virStreamPtr st, int events, void *opaque) {
+    VALUE passthrough = (VALUE)opaque;
+    VALUE cb;
+    VALUE cb_opaque;
+    VALUE news;
+    VALUE s;
+
+    if (TYPE(passthrough) != T_ARRAY)
+        rb_raise(rb_eTypeError,
+                 "wrong domain event lifecycle callback argument type (expected Array)");
+
+    if (RARRAY_LEN(passthrough) != 3)
+        rb_raise(rb_eArgError, "wrong number of arguments (%d for 3)",
+                 RARRAY_LEN(passthrough));
+
+    cb = rb_ary_entry(passthrough, 0);
+    cb_opaque = rb_ary_entry(passthrough, 1);
+    s = rb_ary_entry(passthrough, 2);
+
+    news = stream_new(st, conn_attr(s));
+    if (strcmp(rb_obj_classname(cb), "Symbol") == 0)
+        rb_funcall(rb_class_of(cb), rb_to_id(cb), 3, news, INT2NUM(events),
+                   cb_opaque);
+    else if (strcmp(rb_obj_classname(cb), "Proc") == 0)
+        rb_funcall(cb, rb_intern("call"), 3, news, INT2NUM(events), cb_opaque);
+    else
+        rb_raise(rb_eTypeError,
+                 "wrong stream event callback (expected Symbol or Proc)");
+}
+
+/*
+ * call-seq:
+ *   stream.event_add_callback(events, callback, opaque=nil) -> nil
+ *
+ * Call +virStreamEventAddCallback+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamEventAddCallback]
+ * to register a callback to be notified when a stream becomes readable or
+ * writeable.  The events parameter is an integer representing the events the
+ * user is interested in; it should be one or more of EVENT_READABLE,
+ * EVENT_WRITABLE, EVENT_ERROR, and EVENT_HANGUP, ORed together.  The callback
+ * can either be a Symbol (that is the name of a method to callback) or a Proc.
+ * The callback should accept 3 parameters: a pointer to the Stream object
+ * itself, the integer that represents the events that actually occurred, and
+ * an opaque pointer that was (optionally) passed into
+ * stream.event_add_callback to begin with.
+ */
+static VALUE libvirt_stream_event_add_callback(int argc, VALUE *argv, VALUE s) {
+    VALUE events;
+    VALUE callback;
+    VALUE opaque;
+    VALUE passthrough;
+    int ret;
+
+    rb_scan_args(argc, argv, "21", &events, &callback, &opaque);
+
+    if (!is_symbol_or_proc(callback))
+        rb_raise(rb_eTypeError, "wrong argument type (expected Symbol or Proc)");
+
+    passthrough = rb_ary_new();
+    rb_ary_store(passthrough, 0, callback);
+    rb_ary_store(passthrough, 1, opaque);
+    rb_ary_store(passthrough, 2, s);
+
+    ret = virStreamEventAddCallback(stream_get(s), NUM2INT(events),
+                                    stream_event_callback, (void *)passthrough,
+                                    NULL);
+    _E(ret < 0, create_error(e_RetrieveError, "virStreamEventAddCallback",
+                             conn(s)));
+
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *   stream.event_update_callback(events) -> nil
+ *
+ * Call +virStreamEventUpdateCallback+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamEventUpdateCallback]
+ * to change the events that the event callback is looking for.  The events
+ * parameter is an integer representing the events the user is interested in;
+ * it should be one or more of EVENT_READABLE, EVENT_WRITABLE, EVENT_ERROR,
+ * and EVENT_HANGUP, ORed together.
+ */
+static VALUE libvirt_stream_event_update_callback(VALUE s, VALUE events) {
+    int ret;
+
+    ret = virStreamEventUpdateCallback(stream_get(s), NUM2INT(events));
+    _E(ret < 0, create_error(e_RetrieveError, "virStreamEventUpdateCallback",
+                             conn(s)));
+
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *   stream.event_remove_callback -> nil
+ *
+ * Call +virStreamEventRemoveCallback+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamEventRemoveCallback]
+ * to remove the event callback currently registered to this stream.
+ */
+static VALUE libvirt_stream_event_remove_callback(VALUE s) {
+    int ret;
+
+    ret = virStreamEventRemoveCallback(stream_get(s));
+    _E(ret < 0, create_error(e_RetrieveError, "virStreamEventRemoveCallback",
+                             conn(s)));
+
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *   stream.finish -> nil
+ *
+ * Call +virStreamFinish+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamFinish]
+ * to finish this stream.  Finish is typically used when the stream is no
+ * longer needed and needs to be cleaned up.
+ */
+static VALUE libvirt_stream_finish(VALUE s) {
+    gen_call_void(virStreamFinish, conn(s), stream_get(s));
+}
+
+/*
+ * call-seq:
+ *   stream.abort -> nil
+ *
+ * Call +virStreamAbort+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamAbort]
+ * to abort this stream.  Abort is typically used when something on the stream
+ * has failed, and the stream needs to be cleaned up.
+ */
+static VALUE libvirt_stream_abort(VALUE s) {
+    gen_call_void(virStreamAbort, conn(s), stream_get(s));
+}
+
+/*
+ * call-seq:
+ *   stream.free -> nil
+ *
+ * Call +virStreamFree+[http://www.libvirt.org/html/libvirt-libvirt.html#virStreamFree]
+ * to free this stream.  The object will no longer be valid after this call.
+ */
+static VALUE libvirt_stream_free(VALUE s) {
+    gen_call_free(Stream, s);
+}
+#endif
+
+/*
+ * Class Libvirt::Domain
+ */
+void init_stream()
+{
+#if HAVE_TYPE_VIRSTREAMPTR
+    c_stream = rb_define_class_under(m_libvirt, "Stream", rb_cObject);
+
+    rb_define_attr(c_stream, "connection", 1, 0);
+
+    rb_define_const(c_stream, "NONBLOCK", INT2NUM(VIR_STREAM_NONBLOCK));
+
+    rb_define_const(c_stream, "EVENT_READABLE",
+                    INT2NUM(VIR_STREAM_EVENT_READABLE));
+    rb_define_const(c_stream, "EVENT_WRITABLE",
+                    INT2NUM(VIR_STREAM_EVENT_WRITABLE));
+    rb_define_const(c_stream, "EVENT_ERROR", INT2NUM(VIR_STREAM_EVENT_ERROR));
+    rb_define_const(c_stream, "EVENT_HANGUP", INT2NUM(VIR_STREAM_EVENT_HANGUP));
+
+    rb_define_method(c_stream, "send", libvirt_stream_send, 1);
+    rb_define_method(c_stream, "recv", libvirt_stream_recv, 2);
+    rb_define_method(c_stream, "sendall", libvirt_stream_sendall, -1);
+    rb_define_method(c_stream, "recvall", libvirt_stream_recvall, -1);
+
+    rb_define_method(c_stream, "event_add_callback",
+                     libvirt_stream_event_add_callback, -1);
+    rb_define_method(c_stream, "event_update_callback",
+                     libvirt_stream_event_update_callback, 1);
+    rb_define_method(c_stream, "event_remove_callback",
+                     libvirt_stream_event_remove_callback, 0);
+    rb_define_method(c_stream, "finish", libvirt_stream_finish, 0);
+    rb_define_method(c_stream, "abort", libvirt_stream_abort, 0);
+    rb_define_method(c_stream, "free", libvirt_stream_free, 0);
+#endif
+}
diff --git a/ext/libvirt/stream.h b/ext/libvirt/stream.h
new file mode 100644
index 0000000..094c6e9
--- /dev/null
+++ b/ext/libvirt/stream.h
@@ -0,0 +1,7 @@
+#ifndef STREAM_H
+#define STREAM_H
+
+virStreamPtr stream_get(VALUE s);
+void init_stream();
+
+#endif
diff --git a/tests/tc_connect.rb b/tests/tc_connect.rb
deleted file mode 100644
index 81bb208..0000000
--- a/tests/tc_connect.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-require 'test/unit'
-
-$:.unshift(File::join(File::dirname(__FILE__), "..", "lib"))
-$:.unshift(File::join(File::dirname(__FILE__), "..", "ext", "libvirt"))
-require 'libvirt'
-
-class TestConnect < Test::Unit::TestCase
-
-    LIBVIRT_VERSION = Libvirt::version("Test")[0]
-
-    TEST_CAPS_OLD = "<capabilities>\n  <host>\n    <cpu>\n      <arch>i686</arch>\n      <features>\n        <pae/>\n        <nonpae/>\n      </features>\n    </cpu>\n  </host>\n\n  <guest>\n    <os_type>linux</os_type>\n    <arch name=\"i686\">\n      <wordsize>32</wordsize>\n      <domain type=\"test\"/>\n    </arch>\n    <features>\n      <pae/>\n      <nonpae/>\n    </features>\n  </guest>\n</capabilities>\n"
-
-    TEST_CAPS_0_40_1 = "<capabilities>\n\n  <host>\n    <cpu>\n      <arch>i686</arch>\n      <features>\n        <pae/>\n        <nonpae/>\n      </features>\n    </cpu>\n    <topology>\n      <cells num='2'>\n        <cell id='0'>\n          <cpus num='8'>\n            <cpu id='0'>\n            <cpu id='2'>\n            <cpu id='4'>\n            <cpu id='6'>\n            <cpu id='8'>\n            <cpu id='10'>\n            <cpu id='12'>\n            <cpu id='14'>\n          </cpus>\n        </cell>\n        <cell id='1'>\n          <cpus num='8'>\n            <cpu id='1'>\n            <cpu id='3'>\n            <cpu id='5'>\n            <cpu id='7'>\n            <cpu id='9'>\n            <cpu id='11'>\n            <cpu id='13'>\n            <cpu id='15'>\n          </cpus>\n        </cell>\n      </cells>\n    </topology>\n  </host>\n\n  <guest>\n    <os_type>linux</os_type>\n    <arch name='i686'>\n      <wordsize>32</wordsize>\n      <domain type='test'>\n      </domain>\n    </arch>\n    <features>\n      <pae/>\n      <nonpae/>\n    </features>\n  </guest>\n\n</capabilities>\n"
-
-    if LIBVIRT_VERSION.major >= 0 &&
-            LIBVIRT_VERSION.minor >= 4 &&
-            LIBVIRT_VERSION.release >= 1
-        TEST_CAPS = TEST_CAPS_0_40_1
-    else
-        TEST_CAPS = TEST_CAPS_OLD
-    end
-
-    UUID = "004b96e1-2d78-c30f-5aa5-f03c87d21e69"
-
-    NETWORK_XML = "<network>
-  <name>local</name>
-  <uuid>9b562b27-0969-4b39-8c96-ef7858152ccc</uuid>
-  <bridge name='virbr0'/>
-  <forward/>
-  <ip address='172.31.122.1' netmask='255.255.255.0'>
-    <dhcp>
-      <range start='172.31.122.2' end='172.31.122.254'/>
-    </dhcp>
-  </ip>
-</network>
-"
-
-    def connect_default
-        c = Libvirt::open("test:///default")
-        assert_not_nil(c)
-        assert(! c.closed?)
-        return c
-    end
-
-    def test_open
-        c = connect_default
-        assert_nothing_raised {
-            c.close
-        }
-        assert(c.closed?)
-        assert_nothing_raised {
-            c.close
-        }
-        assert(c.closed?)
-    end
-
-    def test_node_info
-        ni = connect_default.node_get_info
-        assert_equal(2, ni.nodes)
-        assert_equal(16, ni.cpus)
-        assert_equal(2, ni.threads)
-        assert_equal(2, ni.sockets)
-        assert_equal(1400, ni.mhz)
-        assert_equal(2, ni.cores)
-        assert_equal("i686", ni.model)
-    end
-
-    def test_misc
-        c = connect_default
-        assert_equal("Test", c.type)
-        assert_equal(2, c.version)
-        hostname=`hostname`.chomp
-        assert_equal(hostname, c.hostname)
-        assert_equal("test:///default", c.uri)
-        assert_equal(32, c.max_vcpus("bogus"))
-        assert_equal(TEST_CAPS, c.capabilities)
-        assert_equal(1, c.num_of_domains)
-        assert_equal([1], c.list_domains)
-        assert_equal(0, c.num_of_defined_domains)
-        assert_equal([], c.list_defined_domains)
-        assert_equal(1, c.num_of_networks)
-        assert_equal(["default"], c.list_networks)
-        assert_equal(0, c.num_of_defined_networks)
-        assert_equal([], c.list_defined_networks)
-
-        v = Libvirt::version("Test")
-        assert_equal("libvirt", v[0].type)
-        assert_equal("Test", v[1].type)
-    end
-
-    def test_domain
-        c = connect_default;
-
-        dom = c.lookup_domain_by_id(1)
-        assert_equal("test", dom.name)
-        assert_equal("linux", dom.os_type)
-        assert_equal(UUID, dom.uuid)
-        assert_equal(UUID, c.lookup_domain_by_uuid(UUID).uuid)
-        assert_equal(UUID, c.lookup_domain_by_name("test").uuid)
-
-        info = dom.info
-        assert_equal(8388608, info.max_mem)
-        assert_equal(2097152, info.memory)
-        assert_equal(2, info.nr_virt_cpu)
-        assert_equal(Libvirt::Domain::RUNNING, info.state)
-
-        dom.memory = info.memory/2
-        dom.vcpus = 1
-        info = dom.info
-        assert_equal(2097152/2, info.memory)
-        assert_equal(1, info.nr_virt_cpu)
-
-        # pin_vcpu is not implemented in the test driver
-        # enable this once it becomes available
-        # dom.pin_vcpu(0,[0])
-
-        dom.free()
-        assert_raise ArgumentError do
-            dom.name
-        end
-    end
-
-    def test_error
-        c = connect_default;
-        raised = false;
-        begin
-            c.lookup_domain_by_id(42)
-        rescue Libvirt::RetrieveError => e
-            raised = true
-            assert(e.message.size > 0)
-            assert_equal("virDomainLookupByID", e.libvirt_function_name)
-            assert_not_nil e.libvirt_message
-        end
-        assert(raised)
-    end
-
-    def test_network
-        c = connect_default;
-
-        netw = c.lookup_network_by_name("default")
-        assert_equal("default", netw.name)
-        assert_equal("default", netw.bridge_name)
-        assert_equal(UUID, netw.uuid)
-        assert_equal(UUID, c.lookup_network_by_uuid(UUID).uuid)
-        assert_equal(UUID, c.lookup_network_by_name("default").uuid)
-        assert_equal(false, netw.autostart)
-        netw.autostart = true
-        assert_equal(true, netw.autostart)
-        netw.autostart = false
-        assert_equal(false, netw.autostart)
-
-        netw = c.define_network_xml(NETWORK_XML)
-        assert_equal(NETWORK_XML, netw.xml_desc(nil))
-        assert_equal(c, netw.connection)
-
-        assert_equal(2, c.num_of_networks)
-        assert_equal(["default", "local"], c.list_networks)
-
-        netw.free
-        assert_raise ArgumentError do
-            netw.name
-        end
-    end
-end
diff --git a/tests/test_conn.rb b/tests/test_conn.rb
new file mode 100644
index 0000000..65c1a75
--- /dev/null
+++ b/tests/test_conn.rb
@@ -0,0 +1,673 @@
+#!/usr/bin/ruby
+
+# Test the conn methods the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+# test setup
+begin
+  `rm -f /etc/sysconfig/network-scripts/ifcfg-ruby-libvirt-tester`
+  `brctl delbr ruby-libvirt-tester >& /dev/null`
+rescue
+end
+`rm -f #{$GUEST_DISK} ; qemu-img create -f qcow2 #{$GUEST_DISK} 5G`
+`rm -f /var/lib/libvirt/images/ruby-libvirt-test.save`
+`rm -rf #{$POOL_PATH}; mkdir #{$POOL_PATH} ; echo $?`
+
+conn = Libvirt::open("qemu:///system")
+
+cpu_xml = <<EOF
+<cpu>
+  <arch>x86_64</arch>
+  <model>athlon</model>
+</cpu>
+EOF
+
+# TESTGROUP: conn.close
+conn2 = Libvirt::open("qemu:///system")
+expect_too_many_args(conn2, "close", 1)
+expect_success(conn2, "no args", "close")
+
+# TESTGROUP: conn.closed?
+conn2 = Libvirt::open("qemu:///system")
+
+expect_too_many_args(conn2, "closed?", 1)
+expect_success(conn2, "no args", "closed?") {|x| x == false }
+conn2.close
+expect_success(conn2, "no args", "closed?") {|x| x == true }
+
+# TESTGROUP: conn.type
+expect_too_many_args(conn, "type", 1)
+
+expect_success(conn, "no args", "type") {|x| x == "QEMU"}
+
+# TESTGROUP: conn.version
+expect_too_many_args(conn, "version", 1)
+
+expect_success(conn, "no args", "version")
+
+# TESTGROUP: conn.libversion
+expect_too_many_args(conn, "libversion", 1)
+
+expect_success(conn, "no args", "libversion")
+
+# TESTGROUP: conn.hostname
+expect_too_many_args(conn, "hostname", 1)
+
+expect_success(conn, "no args", "hostname")
+
+# TESTGROUP: conn.uri
+expect_too_many_args(conn, "uri", 1)
+
+expect_success(conn, "no args", "uri") {|x| x == "qemu:///system" }
+
+# TESTGROUP: conn.max_vcpus
+expect_too_many_args(conn, "max_vcpus", 'kvm', 1)
+expect_fail(conn, Libvirt::RetrieveError, "invalid arg", "max_vcpus", "foo")
+
+expect_success(conn, "no args", "max_vcpus")
+expect_success(conn, "nil arg", "max_vcpus")
+expect_success(conn, "kvm arg", "max_vcpus")
+expect_success(conn, "qemu arg", "max_vcpus")
+
+# TESTGROUP: conn.node_get_info
+expect_too_many_args(conn, "node_get_info", 1)
+
+expect_success(conn, "no args", "node_get_info")
+
+begin
+  # TESTGROUP: conn.node_free_memory
+  expect_too_many_args(conn, "node_free_memory", 1)
+
+  conn.node_free_memory
+  puts_ok "conn.node_free_memory no args"
+rescue Libvirt::RetrieveError
+  puts_skipped "conn.node_free_memory not supported on this host"
+rescue NoMethodError
+  puts_skipped "conn.node_free_memory does not exist"
+end
+
+begin
+  # TESTGROUP: conn.node_cells_free_memory
+  expect_too_many_args(conn, "node_cells_free_memory", 1, 2, 3)
+  expect_invalid_arg_type(conn, "node_cells_free_memory", 'start')
+  expect_invalid_arg_type(conn, "node_cells_free_memory", 0, 'end')
+
+  cell_mem = conn.node_cells_free_memory
+  puts_ok "conn.node_cells_free_memory no args = "
+  cell_mem = conn.node_cells_free_memory(0)
+  puts_ok "conn.node_cells_free_memory(0) = "
+  cell_mem = conn.node_cells_free_memory(0, 1)
+  puts_ok "conn.node_cells_free_memory(0, 1) = "
+rescue Libvirt::RetrieveError
+  puts_skipped "conn.node_cells_free_memory not supported on this host"
+rescue NoMethodError
+  puts_skipped "conn.node_cells_free_memory does not exist"
+end
+
+# TESTGROUP: conn.node_get_security_model
+expect_too_many_args(conn, "node_get_security_model", 1)
+expect_success(conn, "no args", "node_get_security_model")
+
+# TESTGROUP: conn.encrypted?
+expect_too_many_args(conn, "encrypted?", 1)
+expect_success(conn, "no args", "encrypted?")
+
+# TESTGROUP: conn.secure?
+expect_too_many_args(conn, "secure?", 1)
+expect_success(conn, "no args", "secure?") {|x| x == true}
+
+# TESTGROUP: conn.capabilities
+expect_too_many_args(conn, "capabilities", 1)
+expect_success(conn, "no args", "capabilities")
+
+# TESTGROUP: conn.compare_cpu
+expect_too_many_args(conn, "compare_cpu", 1, 2, 3)
+expect_too_few_args(conn, "compare_cpu")
+expect_invalid_arg_type(conn, "compare_cpu", 1)
+expect_invalid_arg_type(conn, "compare_cpu", "hello", 'bar')
+expect_fail(conn, Libvirt::RetrieveError, "invalid XML", "compare_cpu", "hello")
+expect_success(conn, "CPU XML", "compare_cpu", cpu_xml)
+
+# TESTGROUP: conn.baseline_cpu
+expect_too_many_args(conn, "baseline_cpu", 1, 2, 3)
+expect_too_few_args(conn, "baseline_cpu")
+expect_invalid_arg_type(conn, "baseline_cpu", 1)
+expect_invalid_arg_type(conn, "baseline_cpu", [], "foo")
+expect_fail(conn, ArgumentError, "empty array", "baseline_cpu", [])
+expect_success(conn, "CPU XML", "baseline_cpu", [cpu_xml])
+
+# TESTGROUP: conn.domain_event_register_any
+dom_event_callback_proc = lambda {|conn, dom, event, detail, opaque|
+}
+
+def dom_event_callback_symbol(conn, dom, event, detail, opaque)
+end
+
+expect_too_many_args(conn, "domain_event_register_any", 1, 2, 3, 4, 5)
+expect_too_few_args(conn, "domain_event_register_any")
+expect_too_few_args(conn, "domain_event_register_any", 1)
+expect_invalid_arg_type(conn, "domain_event_register_any", "hello", 1)
+expect_invalid_arg_type(conn, "domain_event_register_any", Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE, 1)
+expect_invalid_arg_type(conn, "domain_event_register_any", Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE, dom_event_callback_proc, 1)
+expect_fail(conn, ArgumentError, "invalid event ID", "domain_event_register_any", 456789, dom_event_callback_proc)
+
+callbackID = expect_success(conn, "eventID and proc", "domain_event_register_any", Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE, dom_event_callback_proc)
+conn.domain_event_deregister_any(callbackID)
+
+callbackID = expect_success(conn, "eventID and symbol", "domain_event_register_any", Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE, :dom_event_callback_symbol)
+conn.domain_event_deregister_any(callbackID)
+
+callbackID = expect_success(conn, "eventID, proc, nil domain", "domain_event_register_any", Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE, dom_event_callback_proc, nil)
+conn.domain_event_deregister_any(callbackID)
+
+callbackID = expect_success(conn, "eventID, proc, nil domain, opaque", "domain_event_register_any", Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE, dom_event_callback_proc, nil, "opaque user data")
+conn.domain_event_deregister_any(callbackID)
+
+# TESTGROUP: conn.domain_event_deregister_any
+dom_event_callback_proc = lambda {|conn, dom, event, detail, opaque|
+}
+
+callbackID = conn.domain_event_register_any(Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE, dom_event_callback_proc)
+
+expect_too_many_args(conn, "domain_event_deregister_any", 1, 2)
+expect_too_few_args(conn, "domain_event_deregister_any")
+expect_invalid_arg_type(conn, "domain_event_deregister_any", "hello")
+
+expect_success(conn, "callbackID", "domain_event_deregister_any", callbackID)
+
+# TESTGROUP: conn.domain_event_register
+dom_event_callback_proc = lambda {|conn, dom, event, detail, opaque|
+}
+
+def dom_event_callback_symbol(conn, dom, event, detail, opaque)
+end
+
+expect_too_many_args(conn, "domain_event_register", 1, 2, 3)
+expect_too_few_args(conn, "domain_event_register")
+expect_invalid_arg_type(conn, "domain_event_register", "hello")
+
+expect_success(conn, "proc", "domain_event_register", dom_event_callback_proc)
+conn.domain_event_deregister
+
+expect_success(conn, "symbol", "domain_event_register", :dom_event_callback_symbol)
+conn.domain_event_deregister
+
+expect_success(conn, "proc and opaque", "domain_event_register", dom_event_callback_proc, "opaque user data")
+conn.domain_event_deregister
+
+# TESTGROUP: conn.domain_event_deregister
+dom_event_callback_proc = lambda {|conn, dom, event, detail, opaque|
+}
+
+conn.domain_event_register(dom_event_callback_proc)
+
+expect_too_many_args(conn, "domain_event_deregister", 1)
+expect_success(conn, "no args", "domain_event_deregister")
+
+# TESTGROUP: conn.num_of_domains
+expect_too_many_args(conn, "num_of_domains", 1)
+expect_success(conn, "no args", "num_of_domains")
+
+# TESTGROUP: conn.list_domains
+expect_too_many_args(conn, "list_domains", 1)
+expect_success(conn, "no args", "list_domains")
+
+# TESTGROUP: conn.num_of_defined_domains
+expect_too_many_args(conn, "num_of_defined_domains", 1)
+expect_success(conn, "no args", "num_of_defined_domains")
+
+# TESTGROUP: conn.list_defined_domains
+expect_too_many_args(conn, "list_defined_domains", 1)
+expect_success(conn, "no args", "list_defined_domains")
+
+# TESTGROUP: conn.create_domain_linux
+expect_too_many_args(conn, "create_domain_linux", $new_dom_xml, 0, 1)
+expect_too_few_args(conn, "create_domain_linux")
+expect_invalid_arg_type(conn, "create_domain_linux", nil)
+expect_invalid_arg_type(conn, "create_domain_linux", 1)
+expect_invalid_arg_type(conn, "create_domain_linux", $new_dom_xml, "foo")
+expect_fail(conn, Libvirt::Error, "invalid xml", "create_domain_linux", "hello")
+newdom = expect_success(conn, "domain xml", "create_domain_linux", $new_dom_xml) {|x| x.class == Libvirt::Domain}
+sleep 1
+
+expect_fail(conn, Libvirt::Error, "already existing domain", "create_domain_linux", $new_dom_xml)
+
+newdom.destroy
+
+# TESTGROUP: conn.create_domain_xml
+expect_too_many_args(conn, "create_domain_xml", $new_dom_xml, 0, 1)
+expect_too_few_args(conn, "create_domain_xml")
+expect_invalid_arg_type(conn, "create_domain_xml", nil)
+expect_invalid_arg_type(conn, "create_domain_xml", 1)
+expect_invalid_arg_type(conn, "create_domain_xml", $new_dom_xml, "foo")
+expect_fail(conn, Libvirt::Error, "invalid xml", "create_domain_xml", "hello")
+newdom = expect_success(conn, "domain xml", "create_domain_xml", $new_dom_xml) {|x| x.class == Libvirt::Domain}
+sleep 1
+
+expect_fail(conn, Libvirt::Error, "already existing domain", "create_domain_xml", $new_dom_xml)
+
+newdom.destroy
+
+# TESTGROUP: conn.lookup_domain_by_name
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(conn, "lookup_domain_by_name", 1, 2)
+expect_too_few_args(conn, "lookup_domain_by_name")
+expect_invalid_arg_type(conn, "lookup_domain_by_name", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent name arg", "lookup_domain_by_name", "foobarbazsucker")
+
+expect_success(conn, "name arg for running domain", "lookup_domain_by_name", "ruby-libvirt-tester") {|x| x.name == "ruby-libvirt-tester"}
+newdom.destroy
+
+newdom = conn.define_domain_xml($new_dom_xml)
+expect_success(conn, "name arg for defined domain", "lookup_domain_by_name", "ruby-libvirt-tester") {|x| x.name == "ruby-libvirt-tester"}
+newdom.undefine
+
+# TESTGROUP: conn.lookup_domain_by_id
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(conn, "lookup_domain_by_id", 1, 2)
+expect_too_few_args(conn, "lookup_domain_by_id")
+expect_invalid_arg_type(conn, "lookup_domain_by_id", "foo")
+expect_fail(conn, Libvirt::Error, "with negative value", "lookup_domain_by_id", -1)
+
+expect_success(conn, "id arg for running domain", "lookup_domain_by_id", newdom.id)
+newdom.destroy
+
+# TESTGROUP: conn.lookup_domain_by_uuid
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(conn, "lookup_domain_by_uuid", 1, 2)
+expect_too_few_args(conn, "lookup_domain_by_uuid")
+expect_invalid_arg_type(conn, "lookup_domain_by_uuid", 1)
+expect_fail(conn, Libvirt::RetrieveError, "invalid UUID", "lookup_domain_by_uuid", "abcd")
+
+expect_success(conn, "UUID arg for running domain", "lookup_domain_by_uuid", newdom.uuid) {|x| x.uuid == $GUEST_UUID}
+newdom.destroy
+
+newdom = conn.define_domain_xml($new_dom_xml)
+expect_success(conn, "UUID arg for defined domain", "lookup_domain_by_uuid", newdom.uuid) {|x| x.uuid == $GUEST_UUID}
+newdom.undefine
+
+# TESTGROUP: conn.define_domain_xml
+expect_too_many_args(conn, "define_domain_xml", 1, 2)
+expect_too_few_args(conn, "define_domain_xml")
+expect_invalid_arg_type(conn, "define_domain_xml", 1)
+expect_invalid_arg_type(conn, "define_domain_xml", nil)
+expect_fail(conn, Libvirt::DefinitionError, "invalid XML", "define_domain_xml", "hello")
+
+newdom = expect_success(conn, "domain xml arg", "define_domain_xml", $new_dom_xml)
+newdom.undefine
+
+# TESTGROUP: conn.domain_xml_from_native
+expect_too_many_args(conn, "domain_xml_from_native", 1, 2, 3, 4)
+expect_too_few_args(conn, "domain_xml_from_native")
+expect_too_few_args(conn, "domain_xml_from_native", 1)
+expect_invalid_arg_type(conn, "domain_xml_from_native", 1, 2)
+expect_invalid_arg_type(conn, "domain_xml_from_native", nil, 2)
+expect_invalid_arg_type(conn, "domain_xml_from_native", "qemu-argv", 2)
+expect_invalid_arg_type(conn, "domain_xml_from_native", "qemu-argv", nil)
+expect_invalid_arg_type(conn, "domain_xml_from_native", "qemu-argv", "foo", "bar")
+expect_fail(conn, Libvirt::Error, "unsupported first arg", "domain_xml_from_native", "foo", "bar")
+
+expect_success(conn, "qemu-argv and qemu_cmd_line", "domain_xml_from_native", "qemu-argv", $qemu_cmd_line)
+
+# TESTGROUP: conn.domain_xml_to_native
+expect_too_many_args(conn, "domain_xml_to_native", 1, 2, 3, 4)
+expect_too_few_args(conn, "domain_xml_to_native")
+expect_too_few_args(conn, "domain_xml_to_native", 1)
+expect_invalid_arg_type(conn, "domain_xml_to_native", 1, 2)
+expect_invalid_arg_type(conn, "domain_xml_to_native", nil, 2)
+expect_invalid_arg_type(conn, "domain_xml_to_native", "qemu-argv", 2)
+expect_invalid_arg_type(conn, "domain_xml_to_native", "qemu-argv", nil)
+expect_invalid_arg_type(conn, "domain_xml_to_native", "qemu-argv", "foo", "bar")
+expect_fail(conn, Libvirt::Error, "unsupported first arg", "domain_xml_to_native", "foo", "bar")
+
+expect_success(conn, "qemu-argv and domain XML", "domain_xml_to_native", "qemu-argv", $new_dom_xml)
+
+# TESTGROUP: conn.num_of_interfaces
+expect_too_many_args(conn, "num_of_interfaces", 1)
+expect_success(conn, "no args", "num_of_interfaces")
+
+# TESTGROUP: conn.list_interfaces
+expect_too_many_args(conn, "list_interfaces", 1)
+expect_success(conn, "no args", "list_interfaces")
+
+# TESTGROUP: conn.num_of_defined_interfaces
+expect_too_many_args(conn, "num_of_defined_interfaces", 1)
+expect_success(conn, "no args", "num_of_defined_interfaces")
+
+# TESTGROUP: conn.list_defined_interfaces
+expect_too_many_args(conn, "list_defined_interfaces", 1)
+expect_success(conn, "no args", "list_defined_interfaces")
+
+# TESTGROUP: conn.lookup_interface_by_name
+newiface = conn.define_interface_xml($new_interface_xml)
+
+expect_too_many_args(conn, "lookup_interface_by_name", 1, 2)
+expect_too_few_args(conn, "lookup_interface_by_name")
+expect_invalid_arg_type(conn, "lookup_interface_by_name", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent name arg", "lookup_interface_by_name", "foobarbazsucker")
+
+expect_success(conn, "name arg", "lookup_interface_by_name", "ruby-libvirt-tester")
+
+newiface.destroy
+
+expect_success(conn, "name arg", "lookup_interface_by_name", "ruby-libvirt-tester")
+
+newiface.undefine
+
+# TESTGROUP: conn.lookup_interface_by_mac
+newiface = conn.define_interface_xml($new_interface_xml)
+
+expect_too_many_args(conn, "lookup_interface_by_mac", 1, 2)
+expect_too_few_args(conn, "lookup_interface_by_mac")
+expect_invalid_arg_type(conn, "lookup_interface_by_mac", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent mac arg", "lookup_interface_by_mac", "foobarbazsucker")
+
+testiface = find_valid_iface(conn)
+if not testiface.nil?
+  expect_success(conn, "name arg", "lookup_interface_by_mac", testiface.mac) {|x| x.mac == testiface.mac}
+end
+
+newiface.undefine
+
+# TESTGROUP: conn.define_interface_xml
+expect_too_many_args(conn, "define_interface_xml", 1, 2, 3)
+expect_too_few_args(conn, "define_interface_xml")
+expect_invalid_arg_type(conn, "define_interface_xml", 1)
+expect_invalid_arg_type(conn, "define_interface_xml", nil)
+expect_invalid_arg_type(conn, "define_interface_xml", "hello", 'foo')
+expect_fail(conn, Libvirt::DefinitionError, "invalid XML", "define_interface_xml", "hello")
+
+expect_success(conn, "interface XML", "define_interface_xml", $new_interface_xml)
+newiface.undefine
+
+# TESTGROUP: conn.num_of_networks
+expect_too_many_args(conn, "num_of_networks", 1)
+expect_success(conn, "no args", "num_of_networks")
+
+# TESTGROUP: conn.list_networks
+expect_too_many_args(conn, "list_networks", 1)
+expect_success(conn, "no args", "list_networks")
+
+# TESTGROUP: conn.num_of_defined_networks
+expect_too_many_args(conn, "num_of_defined_networks", 1)
+expect_success(conn, "no args", "num_of_defined_networks")
+
+# TESTGROUP: conn.list_defined_networks
+expect_too_many_args(conn, "list_defined_networks", 1)
+expect_success(conn, "no args", "list_defined_networks")
+
+# TESTGROUP: conn.lookup_network_by_name
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(conn, "lookup_network_by_name", 1, 2)
+expect_too_few_args(conn, "lookup_network_by_name")
+expect_invalid_arg_type(conn, "lookup_network_by_name", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent name arg", "lookup_network_by_name", "foobarbazsucker")
+
+expect_success(conn, "name arg", "lookup_network_by_name", "ruby-libvirt-tester")
+newnet.destroy
+
+newnet = conn.define_network_xml($new_net_xml)
+expect_success(conn, "name arg", "lookup_network_by_name", "ruby-libvirt-tester")
+newnet.undefine
+
+# TESTGROUP: conn.lookup_network_by_uuid
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(conn, "lookup_network_by_uuid", 1, 2)
+expect_too_few_args(conn, "lookup_network_by_uuid")
+expect_invalid_arg_type(conn, "lookup_network_by_uuid", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent uuid arg", "lookup_network_by_uuid", "foobarbazsucker")
+
+expect_success(conn, "uuid arg", "lookup_network_by_uuid", $NETWORK_UUID)
+newnet.destroy
+
+newnet = conn.define_network_xml($new_net_xml)
+expect_success(conn, "uuid arg", "lookup_network_by_uuid", $NETWORK_UUID)
+newnet.undefine
+
+# TESTGROUP: conn.create_network_xml
+expect_too_many_args(conn, "create_network_xml", $new_net_xml, 0)
+expect_too_few_args(conn, "create_network_xml")
+expect_invalid_arg_type(conn, "create_network_xml", nil)
+expect_invalid_arg_type(conn, "create_network_xml", 1)
+expect_fail(conn, Libvirt::Error, "invalid xml", "create_network_xml", "hello")
+
+newnet = expect_success(conn, "network XML", "create_network_xml", $new_net_xml)
+
+expect_fail(conn, Libvirt::Error, "already existing network", "create_network_xml", $new_net_xml)
+
+newnet.destroy
+
+# TESTGROUP: conn.define_network_xml
+expect_too_many_args(conn, "define_network_xml", 1, 2)
+expect_too_few_args(conn, "define_network_xml")
+expect_invalid_arg_type(conn, "define_network_xml", 1)
+expect_invalid_arg_type(conn, "define_network_xml", nil)
+expect_fail(conn, Libvirt::DefinitionError, "invalid XML", "define_network_xml", "hello")
+
+newnet = expect_success(conn, "network XML", "define_network_xml", $new_net_xml)
+newnet.undefine
+
+# TESTGROUP: conn.num_of_nodedevices
+expect_too_many_args(conn, "num_of_nodedevices", 1, 2, 3)
+expect_invalid_arg_type(conn, "num_of_nodedevices", 1)
+expect_invalid_arg_type(conn, "num_of_nodedevices", 'foo', 'bar')
+expect_success(conn, "no args", "num_of_nodedevices")
+
+# TESTGROUP: conn.list_nodedevices
+expect_too_many_args(conn, "list_nodedevices", 1, 2, 3)
+expect_invalid_arg_type(conn, "list_nodedevices", 1)
+expect_invalid_arg_type(conn, "list_nodedevices", 'foo', 'bar')
+expect_success(conn, "no args", "list_nodedevices")
+
+# TESTGROUP: conn.lookup_nodedevice_by_name
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(conn, "lookup_nodedevice_by_name", 1, 2)
+expect_too_few_args(conn, "lookup_nodedevice_by_name")
+expect_invalid_arg_type(conn, "lookup_nodedevice_by_name", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent name arg", "lookup_nodedevice_by_name", "foobarbazsucker")
+
+expect_success(conn, "name arg", "lookup_nodedevice_by_name", testnode.name)
+
+# TESTGROUP: conn.create_nodedevice_xml
+expect_too_many_args(conn, "create_nodedevice_xml", 1, 2, 3)
+expect_too_few_args(conn, "create_nodedevice_xml")
+expect_invalid_arg_type(conn, "create_nodedevice_xml", 1)
+expect_invalid_arg_type(conn, "create_nodedevice_xml", "foo", 'bar')
+expect_fail(conn, Libvirt::Error, "invalid XML", "create_nodedevice_xml", "hello")
+
+#expect_success(conn, "nodedevice XML", "create_nodedevice_xml", "<nodedevice/>")
+
+# TESTGROUP: conn.num_of_nwfilters
+expect_too_many_args(conn, "num_of_nwfilters", 1)
+expect_success(conn, "no args", "num_of_nwfilters")
+
+# TESTGROUP: conn.list_nwfilters
+expect_too_many_args(conn, "list_nwfilters", 1)
+expect_success(conn, "no args", "list_nwfilters")
+
+# TESTGROUP: conn.lookup_nwfilter_by_name
+newnw = conn.define_nwfilter_xml($new_nwfilter_xml)
+
+expect_too_many_args(conn, "lookup_nwfilter_by_name", 1, 2)
+expect_too_few_args(conn, "lookup_nwfilter_by_name")
+expect_invalid_arg_type(conn, "lookup_nwfilter_by_name", 1)
+
+expect_success(conn, "name arg", "lookup_nwfilter_by_name", "ruby-libvirt-tester")
+
+newnw.undefine
+
+# TESTGROUP: conn.lookup_nwfilter_by_uuid
+newnw = conn.define_nwfilter_xml($new_nwfilter_xml)
+
+expect_too_many_args(conn, "lookup_nwfilter_by_uuid", 1, 2)
+expect_too_few_args(conn, "lookup_nwfilter_by_uuid")
+expect_invalid_arg_type(conn, "lookup_nwfilter_by_uuid", 1)
+
+expect_success(conn, "uuid arg", "lookup_nwfilter_by_uuid", $NWFILTER_UUID) {|x| x.uuid == $NWFILTER_UUID}
+
+newnw.undefine
+
+# TESTGROUP: conn.define_nwfilter_xml
+expect_too_many_args(conn, "define_nwfilter_xml", 1, 2)
+expect_too_few_args(conn, "define_nwfilter_xml")
+expect_invalid_arg_type(conn, "define_nwfilter_xml", 1)
+expect_invalid_arg_type(conn, "define_nwfilter_xml", nil)
+expect_fail(conn, Libvirt::DefinitionError, "invalid XML", "define_nwfilter_xml", "hello")
+
+newnw = expect_success(conn, "nwfilter XML", "define_nwfilter_xml", $new_nwfilter_xml)
+
+newnw.undefine
+
+# TESTGROUP: conn.num_of_secrets
+expect_too_many_args(conn, "num_of_secrets", 1)
+expect_success(conn, "no args", "num_of_secrets")
+
+# TESTGROUP: conn.list_secrets
+expect_too_many_args(conn, "list_secrets", 1)
+expect_success(conn, "no args", "list_secrets")
+
+# TESTGROUP: conn.lookup_secret_by_uuid
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(conn, "lookup_secret_by_uuid", 1, 2)
+expect_too_few_args(conn, "lookup_secret_by_uuid")
+expect_invalid_arg_type(conn, "lookup_secret_by_uuid", 1)
+
+expect_success(conn, "uuid arg", "lookup_secret_by_uuid", $SECRET_UUID) {|x| x.uuid == $SECRET_UUID}
+
+newsecret.undefine
+
+# TESTGROUP: conn.lookup_secret_by_usage
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(conn, "lookup_secret_by_usage", 1, 2, 3)
+expect_too_few_args(conn, "lookup_secret_by_usage")
+expect_invalid_arg_type(conn, "lookup_secret_by_usage", 'foo', 1)
+expect_invalid_arg_type(conn, "lookup_secret_by_usage", 1, 2)
+expect_fail(conn, Libvirt::RetrieveError, "invalid secret", "lookup_secret_by_usage", Libvirt::Secret::USAGE_TYPE_VOLUME, "foo")
+
+expect_success(conn, "usage type and key", "lookup_secret_by_usage", Libvirt::Secret::USAGE_TYPE_VOLUME, "/var/lib/libvirt/images/mail.img")
+
+newsecret.undefine
+
+# TESTGROUP: conn.define_secret_xml
+expect_too_many_args(conn, "define_secret_xml", 1, 2, 3)
+expect_too_few_args(conn, "define_secret_xml")
+expect_invalid_arg_type(conn, "define_secret_xml", 1)
+expect_invalid_arg_type(conn, "define_secret_xml", nil)
+expect_invalid_arg_type(conn, "define_secret_xml", "hello", 'foo')
+expect_fail(conn, Libvirt::DefinitionError, "invalid XML", "define_secret_xml", "hello")
+
+expect_success(conn, "secret XML", "define_secret_xml", $new_secret_xml)
+
+newsecret.undefine
+
+# TESTGROUP: conn.list_storage_pools
+expect_too_many_args(conn, "list_storage_pools", 1)
+expect_success(conn, "no args", "list_storage_pools")
+
+# TESTGROUP: conn.num_of_storage_pools
+expect_too_many_args(conn, "num_of_storage_pools", 1)
+expect_success(conn, "no args", "num_of_storage_pools")
+
+# TESTGROUP: conn.list_defined_storage_pools
+expect_too_many_args(conn, "list_defined_storage_pools", 1)
+expect_success(conn, "no args", "list_defined_storage_pools")
+
+# TESTGROUP: conn.num_of_defined_storage_pools
+expect_too_many_args(conn, "num_of_defined_storage_pools", 1)
+expect_success(conn, "no args", "num_of_defined_storage_pools")
+
+# TESTGROUP: conn.lookup_storage_pool_by_name
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(conn, "lookup_storage_pool_by_name", 1, 2)
+expect_too_few_args(conn, "lookup_storage_pool_by_name")
+expect_invalid_arg_type(conn, "lookup_storage_pool_by_name", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent name arg", "lookup_storage_pool_by_name", "foobarbazsucker")
+
+expect_success(conn, "name arg", "lookup_storage_pool_by_name", "ruby-libvirt-tester")
+
+newpool.destroy
+
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+expect_success(conn, "name arg", "lookup_storage_pool_by_name", "ruby-libvirt-tester")
+newpool.undefine
+
+# TESTGROUP: conn.lookup_storage_pool_by_uuid
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(conn, "lookup_storage_pool_by_uuid", 1, 2)
+expect_too_few_args(conn, "lookup_storage_pool_by_uuid")
+expect_invalid_arg_type(conn, "lookup_storage_pool_by_uuid", 1)
+expect_fail(conn, Libvirt::RetrieveError, "non-existent uuid arg", "lookup_storage_pool_by_uuid", "foobarbazsucker")
+
+expect_success(conn, "uuid arg", "lookup_storage_pool_by_uuid", $POOL_UUID)
+
+newpool.destroy
+
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_success(conn, "uuid arg", "lookup_storage_pool_by_uuid", $POOL_UUID)
+
+newpool.undefine
+
+# TESTGROUP: conn.create_storage_pool_xml
+expect_too_many_args(conn, "create_storage_pool_xml", $new_storage_pool_xml, 0, 1)
+expect_too_few_args(conn, "create_storage_pool_xml")
+expect_invalid_arg_type(conn, "create_storage_pool_xml", nil)
+expect_invalid_arg_type(conn, "create_storage_pool_xml", 1)
+expect_invalid_arg_type(conn, "create_storage_pool_xml", $new_storage_pool_xml, "foo")
+expect_fail(conn, Libvirt::Error, "invalid xml", "create_storage_pool_xml", "hello")
+
+expect_success(conn, "storage pool XML", "create_storage_pool_xml", $new_storage_pool_xml)
+
+expect_fail(conn, Libvirt::Error, "already existing domain", "create_storage_pool_xml", $new_storage_pool_xml)
+
+newpool.destroy
+
+# TESTGROUP: conn.define_storage_pool_xml
+expect_too_many_args(conn, "define_storage_pool_xml", $new_storage_pool_xml, 0, 1)
+expect_too_few_args(conn, "define_storage_pool_xml")
+expect_invalid_arg_type(conn, "define_storage_pool_xml", nil)
+expect_invalid_arg_type(conn, "define_storage_pool_xml", 1)
+expect_invalid_arg_type(conn, "define_storage_pool_xml", $new_storage_pool_xml, "foo")
+expect_fail(conn, Libvirt::Error, "invalid xml", "define_storage_pool_xml", "hello")
+
+expect_success(conn, "storage pool XML", "define_storage_pool_xml", $new_storage_pool_xml)
+
+newpool.undefine
+
+# TESTGROUP: conn.discover_storage_pool_sources
+expect_too_many_args(conn, "discover_storage_pool_sources", 1, 2, 3, 4)
+expect_too_few_args(conn, "discover_storage_pool_sources")
+expect_invalid_arg_type(conn, "discover_storage_pool_sources", 1)
+expect_invalid_arg_type(conn, "discover_storage_pool_sources", "foo", 1)
+expect_invalid_arg_type(conn, "discover_storage_pool_sources", "foo", "bar", "baz")
+
+expect_fail(conn, Libvirt::Error, "invalid pool type", "discover_storage_pool_sources", "foo")
+
+expect_success(conn, "pool type", "discover_storage_pool_sources", "logical")
+
+# TESTGROUP: conn.sys_info
+expect_too_many_args(conn, "sys_info", 1, 2)
+expect_invalid_arg_type(conn, "sys_info", "foo")
+
+expect_success(conn, "system info", "sys_info")
+
+conn.close
+
+finish_tests
diff --git a/tests/test_domain.rb b/tests/test_domain.rb
new file mode 100644
index 0000000..f3976be
--- /dev/null
+++ b/tests/test_domain.rb
@@ -0,0 +1,1096 @@
+#!/usr/bin/ruby
+
+# Test the domain methods the bindings support.  Note that this tester requires
+# the qemu driver to be enabled and available for use.
+
+# Note that the order of the TESTGROUPs below match the order that the
+# functions are defined in the ext/libvirt/domain.c file
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+conn = Libvirt::open("qemu:///system")
+
+# initial cleanup for previous runs
+begin
+  olddom = conn.lookup_domain_by_name("ruby-libvirt-tester")
+  olddom.destroy
+  olddom.undefine
+rescue
+  # in case we didn't find it, don't do anything
+end
+
+# setup for later tests
+`rm -f #{$GUEST_DISK} ; qemu-img create -f qcow2 #{$GUEST_DISK} 5G`
+`rm -f /var/lib/libvirt/images/ruby-libvirt-test.save`
+
+new_hostdev_xml = <<EOF
+<hostdev mode='subsystem' type='pci' managed='yes'>
+  <source>
+    <address bus='0x45' slot='0x55' function='0x33'/>
+  </source>
+</hostdev>
+EOF
+
+# start tests
+
+# TESTGROUP: dom.migrate
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+dconn = Libvirt::open("qemu:///system")
+
+expect_too_many_args(newdom, "migrate", 1, 2, 3, 4, 5, 6)
+expect_too_few_args(newdom, "migrate")
+expect_fail(newdom, ArgumentError, "invalid connection object", "migrate", "foo")
+expect_invalid_arg_type(newdom, "migrate", dconn, 'foo')
+expect_invalid_arg_type(newdom, "migrate", dconn, 0, 1)
+expect_invalid_arg_type(newdom, "migrate", dconn, 0, 'foo', 1)
+expect_invalid_arg_type(newdom, "migrate", dconn, 0, 'foo', 'bar', 'baz')
+
+# FIXME: how can we make this work?
+#expect_success(newdom, "conn arg", "migrate", dconn)
+
+dconn.close
+
+newdom.destroy
+
+# TESTGROUP: dom.migrate_to_uri
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "migrate_to_uri", 1, 2, 3, 4, 5)
+expect_too_few_args(newdom, "migrate_to_uri")
+expect_invalid_arg_type(newdom, "migrate_to_uri", 1)
+expect_invalid_arg_type(newdom, "migrate_to_uri", "qemu:///system", 'foo')
+expect_invalid_arg_type(newdom, "migrate_to_uri", "qemu:///system", 0, 1)
+expect_invalid_arg_type(newdom, "migrate_to_uri", "qemu:///system", 0, 'foo', 'bar')
+
+#expect_success(newdom, "URI arg", "migrate_to_uri", "qemu://remote/system")
+
+dconn.close
+
+newdom.destroy
+
+# TESTGROUP: dom.migrate_set_max_downtime
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "migrate_set_max_downtime", 1, 2, 3)
+expect_too_few_args(newdom, "migrate_set_max_downtime")
+expect_invalid_arg_type(newdom, "migrate_set_max_downtime", 'foo')
+expect_invalid_arg_type(newdom, "migrate_set_max_downtime", 10, 'foo')
+expect_fail(newdom, Libvirt::Error, "on off domain", "migrate_set_max_downtime", 10)
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+expect_fail(newdom, Libvirt::Error, "while no migration in progress", "migrate_set_max_downtime", 10)
+
+#newdom.migrate_to_uri("qemu://remote/system")
+#expect_success(newdom, "10 second downtime", "migrate_set_max_downtime", 10)
+
+newdom.destroy
+
+# TESTGROUP: dom.shutdown
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "shutdown", 1)
+expect_success(newdom, "no args", "shutdown")
+sleep 1
+newdom.destroy
+
+# TESTGROUP: dom.reboot
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+expect_too_many_args(newdom, "reboot", 1, 2)
+expect_invalid_arg_type(newdom, "reboot", "hello")
+
+# Qemu driver doesn't currently support reboot, so this is going to fail
+begin
+  newdom.reboot
+  puts_ok "dom.reboot succeeded"
+rescue Libvirt::Error => e
+  puts_skipped "dom.reboot not supported, skipped"
+end
+
+sleep 1
+newdom.destroy
+
+# TESTGROUP: dom.destroy
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "destroy", 1)
+expect_success(newdom, "no args", "destroy")
+
+# TESTGROUP: dom.suspend
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "suspend", 1)
+expect_success(newdom, "no args", "suspend")
+newdom.destroy
+
+# TESTGROUP: dom.resume
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_success(newdom, "no args running domain", "resume")
+
+newdom.suspend
+expect_too_many_args(newdom, "resume", 1)
+expect_success(newdom, "no args suspended domain", "resume")
+newdom.destroy
+
+# TESTGROUP: dom.save
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.create
+sleep 1
+
+expect_too_many_args(newdom, "save", 1, 2)
+expect_too_few_args(newdom, "save")
+expect_invalid_arg_type(newdom, "save", 1)
+expect_invalid_arg_type(newdom, "save", nil)
+expect_fail(newdom, Libvirt::Error, "non-existent path", "save", "/this/path/does/not/exist")
+
+expect_success(newdom, "path arg", "save", "/var/lib/libvirt/images/ruby-libvirt-test.save")
+
+`rm -f /var/lib/libvirt/images/ruby-libvirt-test.save`
+newdom.undefine
+
+# TESTGROUP: dom.managed_save
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.create
+sleep 1
+
+expect_too_many_args(newdom, "managed_save", 1, 2)
+expect_invalid_arg_type(newdom, "managed_save", "hello")
+expect_success(newdom, "no args", "managed_save")
+newdom.undefine
+
+# TESTGROUP: dom.has_managed_save?
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.create
+sleep 1
+
+expect_too_many_args(newdom, "has_managed_save?", 1, 2)
+expect_invalid_arg_type(newdom, "has_managed_save?", "hello")
+
+if newdom.has_managed_save?
+  puts_fail "dom.has_managed_save? reports true on a new domain"
+else
+  puts_ok "dom.has_managed_save? not true on new domain"
+end
+
+newdom.managed_save
+
+if not newdom.has_managed_save?
+  puts_fail "dom.has_managed_save? reports false after a managed save"
+else
+  puts_ok "dom.has_managed_save? reports true after a managed save"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.managed_save_remove
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.create
+sleep 1
+newdom.managed_save
+
+expect_too_many_args(newdom, "managed_save_remove", 1, 2)
+expect_invalid_arg_type(newdom, "managed_save_remove", "hello")
+
+if not newdom.has_managed_save?
+  puts_fail "prior to dom.managed_save_remove, no managed save file"
+end
+expect_success(newdom, "no args", "managed_save_remove")
+if newdom.has_managed_save?
+  puts_fail "after dom.managed_save_remove, managed save file still exists"
+else
+  puts_ok "after dom.managed_save_remove, managed save file no longer exists"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.core_dump
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.create
+sleep 1
+
+expect_too_many_args(newdom, "core_dump", 1, 2, 3)
+expect_too_few_args(newdom, "core_dump")
+expect_invalid_arg_type(newdom, "core_dump", 1, 2)
+expect_invalid_arg_type(newdom, "core_dump", "/path", "foo")
+expect_fail(newdom, Libvirt::Error, "invalid path", "core_dump", "/this/path/does/not/exist")
+
+expect_success(newdom, "live with path arg", "core_dump", "/var/lib/libvirt/images/ruby-libvirt-test.core")
+
+`rm -f /var/lib/libvirt/images/ruby-libvirt-test.core`
+
+expect_success(newdom, "crash with path arg", "core_dump", "/var/lib/libvirt/images/ruby-libvirt-test.core", Libvirt::Domain::DUMP_CRASH)
+
+expect_fail(newdom, Libvirt::Error, "of shut-off domain", "core_dump", "/var/lib/libvirt/images/ruby-libvirt-test.core", Libvirt::Domain::DUMP_CRASH)
+
+`rm -f /var/lib/libvirt/images/ruby-libvirt-test.core`
+
+newdom.undefine
+
+# TESTGROUP: Libvirt::Domain::restore
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.create
+sleep 1
+newdom.save("/var/lib/libvirt/images/ruby-libvirt-test.save")
+
+expect_too_many_args(Libvirt::Domain, "restore", 1, 2, 3)
+expect_too_few_args(Libvirt::Domain, "restore")
+expect_invalid_arg_type(Libvirt::Domain, "restore", 1, 2)
+expect_invalid_arg_type(Libvirt::Domain, "restore", conn, 2)
+expect_fail(Libvirt::Domain, Libvirt::Error, "invalid path", "restore", conn, "/this/path/does/not/exist")
+`touch /tmp/foo`
+expect_fail(Libvirt::Domain, Libvirt::Error, "invalid save file", "restore", conn, "/tmp/foo")
+`rm -f /tmp/foo`
+
+expect_success(Libvirt::Domain, "2 args", "restore", conn, "/var/lib/libvirt/images/ruby-libvirt-test.save")
+
+`rm -f /var/lib/libvirt/images/ruby-libvirt-test.save`
+
+newdom.destroy
+newdom.undefine
+
+# TESTGROUP: dom.info
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "info", 1)
+
+expect_success(newdom, "no args", "info") {|x| x.state == Libvirt::Domain::RUNNING and x.max_mem == 1048576 and x.memory == 1048576 and x.nr_virt_cpu == 2}
+
+newdom.destroy
+
+# TESTGROUP: dom.security_label
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "security_label", 1)
+
+expect_success(newdom, "no args", "security_label")
+
+newdom.destroy
+
+# TESTGROUP: dom.block_stats
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "block_stats", 1, 2)
+expect_too_few_args(newdom, "block_stats")
+expect_invalid_arg_type(newdom, "block_stats", 1)
+expect_fail(newdom, Libvirt::RetrieveError, "invalid path", "block_stats", "foo")
+
+expect_success(newdom, "block device arg", "block_stats", "vda")
+
+newdom.destroy
+
+# TESTGROUP: dom.memory_stats
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "memory_stats", 1, 2)
+expect_invalid_arg_type(newdom, "memory_stats", "foo")
+
+expect_success(newdom, "no args", "memory_stats")
+
+newdom.destroy
+
+# TESTGROUP: dom.blockinfo
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "blockinfo", 1, 2, 3)
+expect_too_few_args(newdom, "blockinfo")
+expect_invalid_arg_type(newdom, "blockinfo", 1)
+expect_invalid_arg_type(newdom, "blockinfo", "foo", "bar")
+expect_fail(newdom, Libvirt::RetrieveError, "invalid path", "blockinfo", "foo")
+
+expect_success(newdom, "path arg", "blockinfo", $GUEST_DISK)
+
+newdom.destroy
+
+# TESTGROUP: dom.block_peek
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "block_peek", 1, 2, 3, 4, 5)
+expect_too_few_args(newdom, "block_peek")
+expect_too_few_args(newdom, "block_peek", 1)
+expect_too_few_args(newdom, "block_peek", 1, 2)
+expect_invalid_arg_type(newdom, "block_peek", 1, 2, 3)
+expect_invalid_arg_type(newdom, "block_peek", "foo", "bar", 3)
+expect_invalid_arg_type(newdom, "block_peek", "foo", 0, "bar")
+expect_invalid_arg_type(newdom, "block_peek", "foo", 0, 512, "baz")
+expect_fail(newdom, Libvirt::RetrieveError, "invalid path", "block_peek", "foo", 0, 512)
+
+blockpeek = newdom.block_peek($GUEST_DISK, 0, 512)
+
+# 51 46 49 fb are the first 4 bytes of a qcow2 image
+if blockpeek[0] != 0x51 or blockpeek[1] != 0x46 or blockpeek[2] != 0x49 or
+    blockpeek[3] != 0xfb
+  puts_fail "dom.block_peek read did not return valid data"
+else
+  puts_ok "dom.block_peek read valid data"
+end
+
+newdom.destroy
+
+# TESTGROUP: dom.memory_peek
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "memory_peek", 1, 2, 3, 4)
+expect_too_few_args(newdom, "memory_peek")
+expect_too_few_args(newdom, "memory_peek", 1)
+expect_invalid_arg_type(newdom, "memory_peek", "foo", 2)
+expect_invalid_arg_type(newdom, "memory_peek", 0, "bar")
+expect_invalid_arg_type(newdom, "memory_peek", 0, 512, "baz")
+
+expect_success(newdom, "offset and size args", "memory_peek", 0, 512)
+
+newdom.destroy
+
+# TESTGROUP: dom.get_vcpus
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "get_vcpus", 1)
+
+expect_success(newdom, "no args", "get_vcpus") {|x| x.length == 2}
+
+newdom.destroy
+
+# TESTGROUP: dom.active?
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "active?", 1)
+
+expect_success(newdom, "no args", "active?") {|x| x == true}
+
+newdom.destroy
+
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_success(newdom, "no args", "active?") {|x| x == false}
+
+newdom.create
+sleep 1
+
+expect_success(newdom, "no args", "active?") {|x| x == true}
+
+newdom.destroy
+newdom.undefine
+
+# TESTGROUP: dom.persistent?
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "persistent?", 1)
+
+expect_success(newdom, "no args", "persistent?") {|x| x == false}
+
+newdom.destroy
+
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_success(newdom, "no args", "persistent?") {|x| x == true}
+
+newdom.undefine
+
+# TESTGROUP: dom.ifinfo
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "ifinfo", 1, 2)
+expect_too_few_args(newdom, "ifinfo")
+expect_invalid_arg_type(newdom, "ifinfo", 1)
+expect_fail(newdom, Libvirt::RetrieveError, "invalid arg", "ifinfo", "foo")
+
+expect_success(newdom, "interface arg", "ifinfo", "rl556")
+
+newdom.destroy
+
+# TESTGROUP: dom.name
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "name", 1)
+
+expect_success(newdom, "no args", "name") {|x| x == "ruby-libvirt-tester"}
+
+newdom.destroy
+
+# TESTGROUP: dom.id
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "id", 1)
+
+expect_success(newdom, "no args", "id")
+
+newdom.destroy
+
+# TESTGROUP: dom.uuid
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "uuid", 1)
+
+expect_success(newdom, "no args", "uuid") {|x| x == $GUEST_UUID}
+
+newdom.destroy
+
+# TESTGROUP: dom.os_type
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "os_type", 1)
+
+expect_success(newdom, "no args", "os_type") {|x| x == "hvm"}
+
+newdom.destroy
+
+# TESTGROUP: dom.max_memory
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "max_memory", 1)
+
+expect_success(newdom, "no args", "max_memory") {|x| x == 1048576}
+
+newdom.destroy
+
+# TESTGROUP: dom.max_memory=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "max_memory=", 1, 2)
+expect_too_few_args(newdom, "max_memory=")
+expect_invalid_arg_type(newdom, "max_memory=", 'foo')
+
+begin
+  newdom.max_memory = 200000
+  puts_ok "dom.max_memory= succeded"
+rescue NoMethodError
+  puts_skipped "dom.max_memory does not exist"
+rescue Libvirt::DefinitionError => e
+  # dom.max_memory is not supported by Qemu; skip
+  puts_skipped "dom.max_memory not supported by connection driver"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.memory=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "memory=", 1, 2)
+expect_too_few_args(newdom, "memory=")
+expect_invalid_arg_type(newdom, "memory=", 'foo')
+
+expect_fail(newdom, Libvirt::Error, "shutoff domain", "memory=", 2)
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_success(newdom, "number arg", "memory=", 200000)
+
+newdom.destroy
+
+# TESTGROUP: dom.max_vcpus
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "max_vcpus", 1)
+
+expect_success(newdom, "no args", "max_vcpus")
+
+newdom.destroy
+
+# TESTGROUP: dom.vcpus=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "vcpus=", 1, 2)
+expect_too_few_args(newdom, "vcpus=")
+expect_invalid_arg_type(newdom, "vcpus=", 'foo')
+
+expect_fail(newdom, Libvirt::Error, "shutoff domain", "vcpus=", 2)
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+# FIXME: this kills the domain for some reason
+#expect_success(newdom, "number arg", "vcpus=", 2)
+
+newdom.destroy
+
+# TESTGROUP: dom.pin_vcpu
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "pin_vcpu", 1, 2, 3)
+expect_too_few_args(newdom, "pin_vcpu")
+expect_invalid_arg_type(newdom, "pin_vcpu", 'foo', [0])
+expect_invalid_arg_type(newdom, "pin_vcpu", 0, 1)
+
+expect_success(newdom, "cpu args", "pin_vcpu", 0, [0])
+
+newdom.destroy
+
+# TESTGROUP: dom.xml_desc
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_too_many_args(newdom, "xml_desc", 1, 2)
+expect_invalid_arg_type(newdom, "xml_desc", "foo")
+
+expect_success(newdom, "no args", "xml_desc")
+
+newdom.destroy
+
+# TESTGROUP: dom.undefine
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "undefine", 1)
+
+expect_success(newdom, "no args", "undefine")
+
+# TESTGROUP: dom.create
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "create", 1, 2)
+expect_invalid_arg_type(newdom, "create", "foo")
+
+expect_success(newdom, "no args", "create")
+
+expect_fail(newdom, Libvirt::Error, "on already running domain", "create")
+
+newdom.destroy
+newdom.undefine
+
+# TESTGROUP: dom.autostart?
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "autostart?", 1)
+
+expect_success(newdom, "no args", "autostart?") {|x| x == false}
+
+newdom.autostart = true
+
+expect_success(newdom, "no args", "autostart?") {|x| x == true}
+
+newdom.undefine
+
+# TESTGROUP: dom.autostart=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "autostart=", 1, 2)
+expect_invalid_arg_type(newdom, "autostart=", 'foo')
+expect_invalid_arg_type(newdom, "autostart=", nil)
+expect_invalid_arg_type(newdom, "autostart=", 1234)
+
+expect_success(newdom, "true arg", "autostart=", true)
+if not newdom.autostart?
+  puts_fail "dom.autostart= did not set autostart to true"
+else
+  puts_ok "dom.autostart= set autostart to true"
+end
+
+expect_success(newdom, "false arg", "autostart=", false)
+if newdom.autostart?
+  puts_fail "dom.autostart= did not set autostart to false"
+else
+  puts_ok "dom.autostart= set autostart to false"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.attach_device
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "attach_device", 1, 2, 3)
+expect_too_few_args(newdom, "attach_device")
+expect_invalid_arg_type(newdom, "attach_device", 1)
+expect_invalid_arg_type(newdom, "attach_device", 'foo', 'bar')
+expect_fail(newdom, Libvirt::Error, "invalid XML", "attach_device", "hello")
+expect_fail(newdom, Libvirt::Error, "shut off domain", "attach_device", new_hostdev_xml)
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+#expect_success(newdom, "hostdev XML", "attach_device", new_hostdev_xml)
+
+newdom.destroy
+
+# TESTGROUP: dom.detach_device
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "detach_device", 1, 2, 3)
+expect_too_few_args(newdom, "detach_device")
+expect_invalid_arg_type(newdom, "detach_device", 1)
+expect_invalid_arg_type(newdom, "detach_device", 'foo', 'bar')
+expect_fail(newdom, Libvirt::Error, "invalid XML", "detach_device", "hello")
+expect_fail(newdom, Libvirt::Error, "shut off domain", "detach_device", new_hostdev_xml)
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+#expect_success(newdom, "hostdev XML", "detach_device", new_hostdev_xml)
+
+newdom.destroy
+
+# TESTGROUP: dom.update_device
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "update_device", 1, 2, 3)
+expect_too_few_args(newdom, "update_device")
+expect_invalid_arg_type(newdom, "update_device", 1)
+expect_invalid_arg_type(newdom, "update_device", 'foo', 'bar')
+expect_fail(newdom, Libvirt::Error, "invalid XML", "update_device", "hello")
+expect_fail(newdom, Libvirt::Error, "shut off domain", "update_device", new_hostdev_xml)
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+#expect_success(newdom, "hostdev XML", "update_device", new_hostdev_xml)
+
+newdom.destroy
+
+# TESTGROUP: dom.free
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.undefine
+expect_too_many_args(newdom, "free", 1)
+
+newdom.free
+puts_ok "dom.free succeeded"
+
+# TESTGROUP: dom.snapshot_create_xml
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "snapshot_create_xml", 1, 2, 3)
+expect_too_few_args(newdom, "snapshot_create_xml")
+expect_invalid_arg_type(newdom, "snapshot_create_xml", 1)
+expect_invalid_arg_type(newdom, "snapshot_create_xml", nil)
+expect_invalid_arg_type(newdom, "snapshot_create_xml", 'foo', 'bar')
+
+expect_success(newdom, "simple XML arg", "snapshot_create_xml", "<domainsnapshot/>")
+
+snaps = newdom.num_of_snapshots
+if snaps != 1
+  puts_fail "dom.snapshot_create_xml after one snapshot has #{snaps} snapshots"
+else
+  puts_ok "dom.snapshot_create_xml after one snapshot has 1 snapshot"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.num_of_snapshots
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "num_of_snapshots", 1, 2)
+expect_invalid_arg_type(newdom, "num_of_snapshots", 'foo')
+
+expect_success(newdom, "no args", "num_of_snapshots") {|x| x == 0}
+
+newdom.snapshot_create_xml("<domainsnapshot/>")
+
+expect_success(newdom, "no args", "num_of_snapshots") {|x| x == 1}
+
+newdom.undefine
+
+# TESTGROUP: dom.list_snapshots
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "list_snapshots", 1, 2)
+expect_invalid_arg_type(newdom, "list_snapshots", 'foo')
+
+expect_success(newdom, "no args", "list_snapshots") {|x| x.length == 0}
+
+newdom.snapshot_create_xml("<domainsnapshot/>")
+
+expect_success(newdom, "no args", "list_snapshots") {|x| x.length == 1}
+
+newdom.undefine
+
+# TESTGROUP: dom.lookup_snapshot_by_name
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.snapshot_create_xml("<domainsnapshot><name>foo</name></domainsnapshot>")
+
+expect_too_many_args(newdom, "lookup_snapshot_by_name", 1, 2, 3)
+expect_too_few_args(newdom, "lookup_snapshot_by_name")
+expect_invalid_arg_type(newdom, "lookup_snapshot_by_name", 1)
+expect_invalid_arg_type(newdom, "lookup_snapshot_by_name", 'foo', 'bar')
+
+expect_success(newdom, "name arg", "lookup_snapshot_by_name", "foo")
+
+newdom.undefine
+
+# TESTGROUP: dom.has_current_snapshot?
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "has_current_snapshot?", 1, 2)
+expect_invalid_arg_type(newdom, "has_current_snapshot?", 'foo')
+
+expect_success(newdom, "no args", "has_current_snapshot?") {|x| x == false}
+
+newdom.snapshot_create_xml("<domainsnapshot><name>foo</name></domainsnapshot>")
+
+expect_success(newdom, "no args", "has_current_snapshot?") {|x| x == true}
+
+newdom.undefine
+
+# TESTGROUP: dom.revert_to_snapshot
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "revert_to_snapshot", 1, 2, 3)
+expect_too_few_args(newdom, "revert_to_snapshot")
+expect_invalid_arg_type(newdom, "revert_to_snapshot", 1)
+expect_invalid_arg_type(newdom, "revert_to_snapshot", nil)
+expect_invalid_arg_type(newdom, "revert_to_snapshot", 'foo')
+
+snap = newdom.snapshot_create_xml("<domainsnapshot><name>foo</name></domainsnapshot>")
+sleep 1
+
+expect_invalid_arg_type(newdom, "revert_to_snapshot", snap, 'foo')
+
+expect_success(newdom, "snapshot arg", "revert_to_snapshot", snap)
+
+newdom.undefine
+
+# TESTGROUP: dom.current_snapshot
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "current_snapshot", 1, 2)
+expect_invalid_arg_type(newdom, "current_snapshot", 'foo')
+expect_fail(newdom, Libvirt::RetrieveError, "with no snapshots", "current_snapshot")
+
+newdom.snapshot_create_xml("<domainsnapshot><name>foo</name></domainsnapshot>")
+
+expect_success(newdom, "no args", "current_snapshot")
+
+newdom.undefine
+
+# TESTGROUP: snapshot.xml_desc
+newdom = conn.define_domain_xml($new_dom_xml)
+snap = newdom.snapshot_create_xml("<domainsnapshot/>")
+
+expect_too_many_args(snap, "xml_desc", 1, 2)
+expect_invalid_arg_type(snap, "xml_desc", 'foo')
+
+expect_success(newdom, "no args", "xml_desc")
+
+newdom.undefine
+
+# TESTGROUP: snapshot.delete
+newdom = conn.define_domain_xml($new_dom_xml)
+snap = newdom.snapshot_create_xml("<domainsnapshot/>")
+
+expect_too_many_args(snap, "delete", 1, 2)
+expect_invalid_arg_type(snap, "delete", 'foo')
+
+expect_success(snap, "no args", "delete")
+
+newdom.undefine
+
+# TESTGROUP: snapshot.free
+newdom = conn.define_domain_xml($new_dom_xml)
+newdom.undefine
+expect_too_many_args(newdom, "free", 1)
+
+expect_success(newdom, "no args", "free")
+
+# TESTGROUP: dom.job_info
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "job_info", 1)
+
+expect_fail(newdom, Libvirt::RetrieveError, "shutoff domain", "job_info")
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_success(newdom, "no args", "job_info")
+
+newdom.destroy
+
+# TESTGROUP: dom.abort_job
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "abort_job", 1)
+
+expect_fail(newdom, Libvirt::Error, "not running domain", "abort_job")
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_fail(newdom, Libvirt::Error, "no active job", "abort_job")
+
+# FIXME: need to start long running job here
+#expect_success(newdom, "no args", "abort_job")
+
+newdom.destroy
+
+# TESTGROUP: dom.scheduler_type
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "scheduler_type", 1)
+
+begin
+  newdom.scheduler_type
+  puts_ok "dom.scheduler_type succeeded"
+rescue NoMethodError
+  puts_skipped "dom.scheduler_type does not exist"
+rescue Libvirt::RetrieveError
+  # this may not be supported (if cgroups aren't configured), so skip it
+  puts_skipped "dom.scheduler_type not supported"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.scheduler_parameters
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "scheduler_parameters", 1)
+
+begin
+  newdom.scheduler_parameters
+  puts_ok "dom.scheduler_parameters succeeded"
+rescue NoMethodError
+  puts_skipped "dom.scheduler_parameters does not exist"
+rescue Libvirt::RetrieveError
+  # this may not be supported (if cgroups aren't configured), so skip it
+  puts_ok "dom.scheduler_parameters not supported"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.scheduler_parameters=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "scheduler_parameters=", 1, 2)
+expect_too_few_args(newdom, "scheduler_parameters=")
+expect_invalid_arg_type(newdom, "scheduler_parameters=", 0)
+
+begin
+  newdom.scheduler_parameters={"cpu_shares"=>512}
+rescue NoMethodError
+  puts_skipped "dom.scheduler_parameters= does not exist"
+rescue Libvirt::RetrieveError
+  # this may not be supported (if cgroups aren't configured), so skip it
+  puts_ok "dom.scheduler_parameters= not supported"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.qemu_monitor_command
+new_test_xml = <<EOF
+<domain type='test'>
+  <name>fc4</name>
+  <uuid>EF86180145B911CB88E3AFBFE5370493</uuid>
+  <os>
+    <type>xen</type>
+    <kernel>/boot/vmlinuz-2.6.15-1.43_FC5guest</kernel>
+    <initrd>/boot/initrd-2.6.15-1.43_FC5guest.img</initrd>
+    <root>/dev/sda1</root>
+    <cmdline> ro selinux=0 3</cmdline>
+  </os>
+  <memory>261072</memory>
+  <currentMemory>131072</currentMemory>
+  <vcpu>1</vcpu>
+  <devices>
+    <disk type='file'>
+      <source file='/u/fc4.img'/>
+      <target dev='sda1'/>
+    </disk>
+    <interface type='bridge'>
+      <source bridge='xenbr0'/>
+      <mac address='aa:00:00:00:00:11'/>
+      <script path='/etc/xen/scripts/vif-bridge'/>
+    </interface>
+    <console tty='/dev/pts/5'/>
+  </devices>
+</domain>
+EOF
+
+newdom = conn.create_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "qemu_monitor_command", 1, 2, 3)
+expect_too_few_args(newdom, "qemu_monitor_command")
+expect_invalid_arg_type(newdom, "qemu_monitor_command", 1)
+expect_invalid_arg_type(newdom, "qemu_monitor_command", "foo", "bar")
+testconn = Libvirt::open("test:///default")
+fakedom = testconn.create_domain_xml(new_test_xml)
+expect_invalid_arg_type(fakedom, "qemu_monitor_command", "foo")
+fakedom.destroy
+testconn.close
+expect_fail(newdom, Libvirt::RetrieveError, "invalid command", "qemu_monitor_command", "foo")
+
+expect_success(newdom, "monitor command", "qemu_monitor_command", '{"execute":"query-cpus"}')
+
+newdom.destroy
+
+# TESTGROUP: dom.num_vcpus
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "num_vcpus", 1, 2)
+expect_too_few_args(newdom, "num_vcpus")
+expect_invalid_arg_type(newdom, "num_vcpus", 'foo')
+expect_fail(newdom, Libvirt::Error, "zero flags", "num_vcpus", 0)
+expect_fail(newdom, Libvirt::Error, "active flag on shutoff domain", "num_vcpus", Libvirt::Domain::VCPU_LIVE)
+expect_fail(newdom, Libvirt::Error, "live and config flags", "num_vcpus", Libvirt::Domain::VCPU_LIVE | Libvirt::Domain::VCPU_CONFIG)
+expect_success(newdom, "config flag", "num_vcpus", Libvirt::Domain::VCPU_CONFIG) {|x| x == 2}
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_success(newdom, "config flag on transient domain", "num_vcpus", Libvirt::Domain::VCPU_CONFIG)
+expect_success(newdom, "live flag on transient domain", "num_vcpus", Libvirt::Domain::VCPU_LIVE)
+
+newdom.destroy
+
+# TESTGROUP: dom.vcpus_flags=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "vcpus_flags=", 1, 2, 3)
+expect_too_few_args(newdom, "vcpus_flags=")
+expect_invalid_arg_type(newdom, "vcpus_flags=", 1)
+expect_invalid_arg_type(newdom, "vcpus_flags=", ['foo', 2])
+expect_invalid_arg_type(newdom, "vcpus_flags=", [2, 'foo'])
+expect_fail(newdom, Libvirt::Error, "zero flags", "vcpus_flags=", [2, 0])
+expect_fail(newdom, Libvirt::Error, "zero vcpus", "vcpus_flags=", [0, Libvirt::Domain::VCPU_CONFIG])
+expect_fail(newdom, Libvirt::Error, "live vcpu on shutoff domain", "vcpus_flags=", [2, Libvirt::Domain::VCPU_LIVE])
+expect_success(newdom, "2 vcpu config", "vcpus_flags=", [2, Libvirt::Domain::VCPU_CONFIG])
+
+newdom.undefine
+
+newdom = conn.create_domain_xml($new_dom_xml)
+sleep 1
+
+expect_fail(newdom, Libvirt::Error, "vcpu config on transient domain", "vcpus_flags=", [2, Libvirt::Domain::VCPU_CONFIG])
+expect_fail(newdom, Libvirt::Error, "too many vcpus", "vcpus_flags=", [4, Libvirt::Domain::VCPU_LIVE])
+
+# FIXME: this doesn't work for some reason
+#expect_success(newdom, "vcpus to 1", "vcpus_flags=", [1, Libvirt::Domain::VCPU_LIVE])
+
+newdom.destroy
+
+# TESTGROUP: dom.memory_parameters=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "memory_parameters=", 1, 2, 3)
+expect_too_few_args(newdom, "memory_parameters=")
+expect_invalid_arg_type(newdom, "memory_parameters=", 0)
+expect_fail(newdom, ArgumentError, "empty array", "memory_parameters=", [])
+expect_invalid_arg_type(newdom, "memory_parameters=", [1, 0])
+expect_invalid_arg_type(newdom, "memory_parameters=", [{}, "foo"])
+
+begin
+  newdom.memory_parameters={"soft_limit" => 9007199254740999, "swap_hard_limit" => 9007199254740999}
+rescue NoMethodError
+  puts_skipped "dom.memory_parameters= does not exist"
+rescue Libvirt::RetrieveError
+  # this may not be supported (if cgroups aren't configured), so skip it
+  puts_skipped "memory_parameters= not supported"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.memory_parameters
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "memory_parameters", 1, 2)
+
+begin
+  newdom.memory_parameters
+  puts_ok "dom.memory_parameters succeeded"
+rescue NoMethodError
+  puts_skipped "memory_parameters does not exist"
+rescue Libvirt::RetrieveError
+  # this may not be supported (if cgroups aren't configured), so skip it
+  puts_skipped "memory_parameters not supported"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.blkio_parameters=
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "blkio_parameters=", 1, 2, 3)
+expect_too_few_args(newdom, "blkio_parameters=")
+expect_invalid_arg_type(newdom, "blkio_parameters=", 0)
+expect_fail(newdom, ArgumentError, "empty array", "blkio_parameters=", [])
+expect_invalid_arg_type(newdom, "blkio_parameters=", [1, 0])
+expect_invalid_arg_type(newdom, "blkio_parameters=", [{}, "foo"])
+
+begin
+  newdom.blkio_parameters={"weight" => 1}
+rescue NoMethodError
+  puts_skipped "blkio_parameters= does not exist"
+rescue Libvirt::RetrieveError
+  # this may not be supported (if cgroups aren't configured), so skip it
+  puts_skipped "blkio_parameters= not supported"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.blkio_parameters
+newdom = conn.define_domain_xml($new_dom_xml)
+
+expect_too_many_args(newdom, "blkio_parameters", 1, 2)
+
+begin
+  newdom.blkio_parameters
+  puts_ok "dom.blkio_parameters succeeded"
+rescue NoMethodError
+  puts_skipped "blkio_parameters does not exist"
+rescue Libvirt::RetrieveError
+  # this may not be supported (if cgroups aren't configured), so skip it
+  puts_skipped "blkio_parameters not supported"
+end
+
+newdom.undefine
+
+# TESTGROUP: dom.open_console
+newdom = conn.create_domain_xml(new_dom_xml)
+stream = conn.stream
+
+expect_too_many_args(newdom, "open_console", 1, 2, 3, 4)
+expect_too_few_args(newdom, "open_console")
+expect_too_few_args(newdom, "open_console", 1)
+expect_invalid_arg_type(newdom, "open_console", 1, stream)
+expect_invalid_arg_type(newdom, "open_console", "pty", 1)
+expect_invalid_arg_type(newdom, "open_console", "pty", stream, "wow")
+
+expect_success(newdom, "device and stream args", "open_console", "pty", stream)
+
+newdom.destroy
+
+conn.close
+
+finish_tests
diff --git a/tests/test_interface.rb b/tests/test_interface.rb
new file mode 100644
index 0000000..b921042
--- /dev/null
+++ b/tests/test_interface.rb
@@ -0,0 +1,106 @@
+#!/usr/bin/ruby
+
+# Test the interface methods the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+def find_valid_iface(conn)
+  conn.list_interfaces.each do |ifname|
+    iface = conn.lookup_interface_by_name(ifname)
+    if iface.mac == "00:00:00:00:00:00"
+      next
+    end
+    return iface
+  end
+end
+
+conn = Libvirt::open("qemu:///system")
+
+# test setup
+begin
+  `rm -f /etc/sysconfig/network-scripts/ifcfg-ruby-libvirt-tester`
+  `brctl delbr ruby-libvirt-tester >& /dev/null`
+rescue
+end
+
+# TESTGROUP: iface.undefine
+newiface = conn.define_interface_xml($new_interface_xml)
+
+expect_too_many_args(newiface, "undefine", 1)
+
+expect_success(newiface, "no args", "undefine")
+
+# TESTGROUP: iface.create
+newiface = conn.define_interface_xml($new_interface_xml)
+
+expect_too_many_args(newiface, "create", 1, 2)
+expect_invalid_arg_type(newiface, "create", 'foo')
+
+#expect_success(newiface, "no args", "create")
+
+#expect_fail(newiface, Libvirt::Error, "on already running interface", "create")
+
+#newiface.destroy
+newiface.undefine
+
+# TESTGROUP: iface.destroy
+newiface = conn.define_interface_xml($new_interface_xml)
+
+expect_too_many_args(newiface, "destroy", 1, 2)
+expect_invalid_arg_type(newiface, "destroy", 'foo')
+
+expect_success(newiface, "no args", "destroy")
+
+newiface.undefine
+
+# TESTGROUP: iface.active?
+newiface = conn.define_interface_xml($new_interface_xml)
+
+expect_too_many_args(newiface, "active?", 1)
+
+expect_success(newiface, "no args", "active?") {|x| x == false}
+
+#newiface.create
+#expect_success(newiface, "no args", "active?") {|x| x == true}
+
+#newiface.destroy
+newiface.undefine
+
+# TESTGROUP: iface.name
+newiface = conn.define_interface_xml($new_interface_xml)
+
+expect_too_many_args(newiface, "name", 1)
+
+expect_success(newiface, "no args", "name") {|x| x == "ruby-libvirt-tester"}
+
+newiface.undefine
+
+# TESTGROUP: iface.mac
+testiface = find_valid_iface(conn)
+if not testiface.nil?
+  expect_too_many_args(testiface, "mac", 1)
+
+  expect_success(testiface, "no args", "mac") {|x| x == testiface.mac}
+end
+
+# TESTGROUP: iface.xml_desc
+testiface = find_valid_iface(conn)
+if not testiface.nil?
+  expect_too_many_args(testiface, "xml_desc", 1, 2)
+  expect_invalid_arg_type(testiface, "xml_desc", "foo")
+  expect_success(testiface, "no args", "xml_desc")
+end
+
+# TESTGROUP: iface.free
+newiface = conn.define_interface_xml($new_interface_xml)
+newiface.undefine
+expect_too_many_args(newiface, "free", 1)
+
+expect_success(newiface, "no args", "free")
+
+conn.close
+
+finish_tests
diff --git a/tests/test_network.rb b/tests/test_network.rb
new file mode 100644
index 0000000..dbe6a0e
--- /dev/null
+++ b/tests/test_network.rb
@@ -0,0 +1,166 @@
+#!/usr/bin/ruby
+
+# Test the network methods the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+conn = Libvirt::open("qemu:///system")
+
+# initial cleanup for previous run
+begin
+  oldnet = conn.lookup_network_by_name("ruby-libvirt-tester")
+  oldnet.destroy
+  oldnet.undefine
+rescue
+  # in case we didn't find it, don't do anything
+end
+
+# TESTGROUP: net.undefine
+newnet = conn.define_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "undefine", 1)
+
+expect_success(newnet, "no args", "undefine")
+
+# TESTGROUP: net.create
+newnet = conn.define_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "create", 1)
+
+expect_success(newnet, "no args", "create")
+
+expect_fail(newnet, Libvirt::Error, "on already running network", "create")
+
+newnet.destroy
+newnet.undefine
+
+# TESTGROUP: net.destroy
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "destroy", 1)
+
+expect_success(newnet, "no args", "destroy")
+
+# TESTGROUP: net.name
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "name", 1)
+
+expect_success(newnet, "no args", "name") {|x| x == "ruby-libvirt-tester"}
+
+newnet.destroy
+
+# TESTGROUP: net.uuid
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "uuid", 1)
+
+expect_success(newnet, "no args", "uuid") {|x| x == $NETWORK_UUID}
+
+newnet.destroy
+
+# TESTGROUP: net.xml_desc
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "xml_desc", 1, 2)
+expect_invalid_arg_type(newnet, "xml_desc", "foo")
+
+expect_success(newnet, "no args", "xml_desc")
+
+newnet.destroy
+
+# TESTGROUP: net.bridge_name
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "bridge_name", 1)
+
+expect_success(newnet, "no args", "bridge_name") {|x| x == "rubybr0"}
+
+newnet.destroy
+
+# TESTGROUP: net.autostart?
+newnet = conn.define_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "autostart?", 1)
+
+expect_success(newnet, "no args", "autostart?") {|x| x == false}
+
+newnet.autostart = true
+
+expect_success(newnet, "no args", "autostart?") {|x| x == true}
+
+newnet.undefine
+
+# TESTGROUP: net.autostart=
+newnet = conn.define_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "autostart=", 1, 2)
+expect_invalid_arg_type(newnet, "autostart=", 'foo')
+expect_invalid_arg_type(newnet, "autostart=", nil)
+expect_invalid_arg_type(newnet, "autostart=", 1234)
+
+expect_success(newnet, "boolean arg", "autostart=", true)
+if not newnet.autostart?
+  puts_fail "net.autostart= did not set autostart to true"
+else
+  puts_ok "net.autostart= set autostart to true"
+end
+
+expect_success(newnet, "boolean arg", "autostart=", false)
+if newnet.autostart?
+  puts_fail "net.autostart= did not set autostart to false"
+else
+  puts_ok "net.autostart= set autostart to false"
+end
+
+newnet.undefine
+
+# TESTGROUP: net.free
+newnet = conn.define_network_xml($new_net_xml)
+newnet.undefine
+expect_too_many_args(newnet, "free", 1)
+
+expect_success(newnet, "no args", "free")
+
+# TESTGROUP: net.active?
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "active?", 1)
+
+expect_success(newnet, "no args", "active?") {|x| x == true}
+
+newnet.destroy
+
+newnet = conn.define_network_xml($new_net_xml)
+
+expect_success(newnet, "no args", "active?") {|x| x == false}
+
+newnet.create
+
+expect_success(newnet, "no args", "active?") {|x| x == true}
+
+newnet.destroy
+newnet.undefine
+
+# TESTGROUP: net.persistent?
+newnet = conn.create_network_xml($new_net_xml)
+
+expect_too_many_args(newnet, "persistent?", 1)
+
+expect_success(newnet, "no args", "persistent?") {|x| x == false}
+
+newnet.destroy
+
+newnet = conn.define_network_xml($new_net_xml)
+
+expect_success(newnet, "no args", "persistent?") {|x| x == true}
+
+newnet.undefine
+
+
+conn.close
+
+finish_tests
diff --git a/tests/test_nodedevice.rb b/tests/test_nodedevice.rb
new file mode 100644
index 0000000..bd05cbb
--- /dev/null
+++ b/tests/test_nodedevice.rb
@@ -0,0 +1,80 @@
+#!/usr/bin/ruby
+
+# Test the nodedevice methods the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+conn = Libvirt::open("qemu:///system")
+
+# TESTGROUP: nodedevice.name
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "name", 1)
+expect_success(testnode, "no args", "name")
+
+# TESTGROUP: nodedevice.parent
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "parent", 1)
+expect_success(testnode, "no args", "parent")
+
+# TESTGROUP: nodedevice.num_of_caps
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "num_of_caps", 1)
+expect_success(testnode, "no args", "num_of_caps")
+
+# TESTGROUP: nodedevice.list_caps
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "list_caps", 1)
+expect_success(testnode, "no args", "list_caps")
+
+# TESTGROUP: nodedevice.xml_desc
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "xml_desc", 1, 2)
+expect_invalid_arg_type(testnode, "xml_desc", 'foo')
+expect_success(testnode, "no args", "xml_desc")
+
+# TESTGROUP: nodedevice.detach
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "detach", 1)
+
+#expect_success(testnode, "no args", "detach")
+
+# TESTGROUP: nodedevice.reattach
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "reattach", 1)
+
+#expect_success(testnode, "no args", "reattach")
+
+# TESTGROUP: nodedevice.reset
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "reset", 1)
+
+#expect_success(testnode, "no args", "reset")
+
+# TESTGROUP: nodedevice.destroy
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "destroy", 1)
+
+#expect_success(testnode, "no args", "destroy")
+
+# TESTGROUP: nodedevice.free
+testnode = conn.lookup_nodedevice_by_name(conn.list_nodedevices[0])
+
+expect_too_many_args(testnode, "free", 1)
+
+expect_success(testnode, "no args", "free")
+
+conn.close
+
+finish_tests
diff --git a/tests/test_nwfilter.rb b/tests/test_nwfilter.rb
new file mode 100644
index 0000000..a059aee
--- /dev/null
+++ b/tests/test_nwfilter.rb
@@ -0,0 +1,56 @@
+#!/usr/bin/ruby
+
+# Test the nwfilter methods the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+conn = Libvirt::open("qemu:///system")
+
+# TESTGROUP: nwfilter.undefine
+newnw = conn.define_nwfilter_xml($new_nwfilter_xml)
+
+expect_too_many_args(newnw, "undefine", 1)
+
+expect_success(newnw, "no args", "undefine")
+
+# TESTGROUP: nwfilter.name
+newnw = conn.define_nwfilter_xml($new_nwfilter_xml)
+
+expect_too_many_args(newnw, "name", 1)
+
+expect_success(newnw, "no args", "name") {|x| x == "ruby-libvirt-tester"}
+
+newnw.undefine
+
+# TESTGROUP: nwfilter.uuid
+newnw = conn.define_nwfilter_xml($new_nwfilter_xml)
+
+expect_too_many_args(newnw, "uuid", 1)
+
+expect_success(newnw, "no args", "uuid") {|x| x == $NWFILTER_UUID}
+
+newnw.undefine
+
+# TESTGROUP: nwfilter.xml_desc
+newnw = conn.define_nwfilter_xml($new_nwfilter_xml)
+
+expect_too_many_args(newnw, "xml_desc", 1, 2)
+expect_invalid_arg_type(newnw, "xml_desc", "foo")
+
+expect_success(newnw, "no args", "xml_desc")
+
+newnw.undefine
+
+# TESTGROUP: nwfilter.free
+newnw = conn.define_nwfilter_xml($new_nwfilter_xml)
+newnw.undefine
+expect_too_many_args(newnw, "free", 1)
+
+expect_success(newnw, "no args", "free")
+
+conn.close
+
+finish_tests
diff --git a/tests/test_open.rb b/tests/test_open.rb
new file mode 100644
index 0000000..6b57ada
--- /dev/null
+++ b/tests/test_open.rb
@@ -0,0 +1,197 @@
+#!/usr/bin/ruby
+
+# Test the open calls that the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+def expect_connect_error(func, args)
+  expect_fail(Libvirt, Libvirt::ConnectionError, "invalid driver", func, *args)
+end
+
+# TESTGROUP: Libvirt::version
+expect_too_many_args(Libvirt, "version", "test", 1)
+expect_invalid_arg_type(Libvirt, "version", 1)
+expect_success(Libvirt, "no args", "version") {|x| x.class == Array and x.length == 2}
+expect_success(Libvirt, "nil arg", "version", nil) {|x| x.class == Array and x.length == 2}
+expect_success(Libvirt, "Test arg", "version", "Test") {|x| x.class == Array and x.length == 2}
+
+# TESTGROUP: Libvirt::open
+expect_too_many_args(Libvirt, "open", "qemu:///system", 1)
+expect_connect_error("open", "foo:///system")
+conn = expect_success(Libvirt, "no args", "open") {|x| x.class == Libvirt::Connect }
+conn.close
+conn = expect_success(Libvirt, "qemu:///system", "open", "qemu:///system") {|x| x.class == Libvirt::Connect }
+conn.close
+conn = expect_success(Libvirt, "nil arg", "open", nil) {|x| x.class == Libvirt::Connect }
+conn.close
+
+# TESTGROUP: Libvirt::open_read_only
+expect_too_many_args(Libvirt, "open_read_only", "qemu:///system", 1)
+expect_connect_error("open_read_only", "foo:///system")
+conn = expect_success(Libvirt, "no args", "open_read_only") {|x| x.class == Libvirt::Connect }
+conn.close
+conn = expect_success(Libvirt, "qemu:///system", "open_read_only", "qemu:///system") {|x| x.class == Libvirt::Connect }
+conn.close
+conn = expect_success(Libvirt, "nil arg", "open_read_only", nil) {|x| x.class == Libvirt::Connect }
+conn.close
+
+# TESTGROUP: Libvirt::open_auth
+expect_too_many_args(Libvirt, "open_auth", "qemu:///system", [], "hello there", 1, 2)
+expect_connect_error("open_auth", "foo:///system")
+expect_invalid_arg_type(Libvirt, "open_auth", 1)
+expect_invalid_arg_type(Libvirt, "open_auth", "qemu:///system", [], "hello", "foo")
+
+conn = expect_success(Libvirt, "no args", "open_auth")  {|x| x.class == Libvirt::Connect }
+conn.close
+
+conn = expect_success(Libvirt, "uri arg", "open_auth", "qemu:///system") {|x| x.class == Libvirt::Connect }
+conn.close
+
+conn = expect_success(Libvirt, "uri and empty cred args", "open_auth", "qemu:///system", []) {|x| x.class == Libvirt::Connect }
+conn.close
+
+conn = expect_success(Libvirt, "uri and full cred args", "open_auth", "qemu:///system", [Libvirt::CRED_AUTHNAME, Libvirt::CRED_PASSPHRASE]) {|x| x.class == Libvirt::Connect }
+conn.close
+
+conn = expect_success(Libvirt, "uri, full cred, and user args", "open_auth", "qemu:///system", [Libvirt::CRED_AUTHNAME, Libvirt::CRED_PASSPHRASE], "hello") {|x| x.class == Libvirt::Connect }
+conn.close
+
+# equivalent to "expect_success"
+begin
+  conn = Libvirt::open_auth("qemu:///system", [Libvirt::CRED_AUTHNAME, Libvirt::CRED_PASSPHRASE], "hello") do |cred|
+    if not cred["userdata"].nil?
+      puts "userdata is #{cred["userdata"]}"
+    end
+    if cred["type"] == Libvirt::CRED_AUTHNAME
+      print "#{cred['prompt']}: "
+      res = gets
+      # strip off the \n
+      res = res[0..-2]
+    elsif cred["type"] == Libvirt::CRED_PASSPHRASE
+      print "#{cred['prompt']}: "
+      res = gets
+      res = res[0..-2]
+    else
+      raise "Unsupported credential #{cred['type']}"
+    end
+    res
+  end
+
+  puts_ok "open_auth uri, creds, userdata, auth block succeeded"
+  conn.close
+rescue NoMethodError
+  puts_skipped "open_auth does not exist"
+rescue => e
+  puts_fail "open_auth uri, creds, userdata, auth block expected to succeed, threw #{e.class.to_s}: #{e.to_s}"
+end
+
+# equivalent to "expect_success"
+begin
+  conn = Libvirt::open_auth("qemu:///system", [Libvirt::CRED_AUTHNAME, Libvirt::CRED_PASSPHRASE], "hello", Libvirt::CONNECT_RO) do |cred|
+    if not cred["userdata"].nil?
+      puts "userdata is #{cred["userdata"]}"
+    end
+    if cred["type"] == Libvirt::CRED_AUTHNAME
+      print "#{cred['prompt']}: "
+      res = gets
+      # strip off the \n
+      res = res[0..-2]
+    elsif cred["type"] == Libvirt::CRED_PASSPHRASE
+      print "#{cred['prompt']}: "
+      res = gets
+      res = res[0..-2]
+    else
+      raise "Unsupported credential #{cred['type']}"
+    end
+    res
+  end
+
+  puts_ok "open_auth uri, creds, userdata, R/O flag, auth block succeeded"
+  conn.close
+rescue NoMethodError
+  puts_skipped "open_auth does not exist"
+rescue => e
+  puts_fail "open_auth uri, creds, userdata, R/O flag, auth block expected to succeed, threw #{e.class.to_s}: #{e.to_s}"
+end
+
+# TESTGROUP: Libvirt::event_invoke_handle_callback
+conn = Libvirt::open("qemu:///system")
+
+expect_too_many_args(Libvirt, "event_invoke_handle_callback", 1, 2, 3, 4, 5)
+expect_too_few_args(Libvirt, "event_invoke_handle_callback")
+expect_too_few_args(Libvirt, "event_invoke_handle_callback", 1)
+expect_too_few_args(Libvirt, "event_invoke_handle_callback", 1, 2)
+expect_too_few_args(Libvirt, "event_invoke_handle_callback", 1, 2, 3)
+# this is a bit bizarre; I am constructing a bogus hash to pass as the 4th
+# parameter to event_invoke_handle_callback.  In a real situation, I would
+# have been given this hash from libvirt earlier, and just pass it on.  I
+# don't want all of that complexity here, though, so I create the bogus hash.
+# One caveat; the data inside the hash *must* be of type T_DATA, so I pass in
+# a fake conn object just to appease the type checker (so I can test out the
+# other arguments properly)
+expect_invalid_arg_type(Libvirt, "event_invoke_handle_callback", "hello", 1, 1, { "libvirt_cb" => conn, "opaque" => conn })
+expect_invalid_arg_type(Libvirt, "event_invoke_handle_callback", 1, "hello", 1, { "libvirt_cb" => conn, "opaque" => conn })
+expect_invalid_arg_type(Libvirt, "event_invoke_handle_callback", 1, 1, "hello", { "libvirt_cb" => conn, "opaque" => conn })
+expect_invalid_arg_type(Libvirt, "event_invoke_handle_callback", 1, 1, 1, { "libvirt_cb" => "hello", "opaque" => conn })
+expect_invalid_arg_type(Libvirt, "event_invoke_handle_callback", 1, 1, 1, { "libvirt_cb" => conn, "opaque" => "hello" })
+conn.close
+
+# TESTGROUP: Libvirt::event_invoke_timeout_callback
+conn = Libvirt::open("qemu:///system")
+
+expect_too_many_args(Libvirt, "event_invoke_timeout_callback", 1, 2, 3)
+expect_too_few_args(Libvirt, "event_invoke_timeout_callback")
+expect_too_few_args(Libvirt, "event_invoke_timeout_callback", 1)
+# this is a bit bizarre; I am constructing a bogus hash to pass as the 4th
+# parameter to event_invoke_handle_callback.  In a real situation, I would
+# have been given this hash from libvirt earlier, and just pass it on.  I
+# don't want all of that complexity here, though, so I create the bogus hash.
+# One caveat; the data inside the hash *must* be of type T_DATA, so I pass in
+# a fake conn object just to appease the type checker (so I can test out the
+# other arguments properly)
+expect_invalid_arg_type(Libvirt, "event_invoke_timeout_callback", "hello", { "libvirt_cb" => conn, "opaque" => conn })
+expect_invalid_arg_type(Libvirt, "event_invoke_timeout_callback", 1, { "libvirt_cb" => "hello", "opaque" => conn })
+expect_invalid_arg_type(Libvirt, "event_invoke_timeout_callback", 1, { "libvirt_cb" => conn, "opaque" => "hello" })
+conn.close
+
+# TESTGROUP: Libvirt::event_register_impl
+expect_too_many_args(Libvirt, "event_register_impl", 1, 2, 3, 4, 5, 6, 7)
+expect_invalid_arg_type(Libvirt, "event_register_impl", 1)
+
+# symbol callbacks
+def virEventAddHandleImpl(fd, events, opaque)
+end
+def virEventUpdateHandleImpl(watch, event)
+end
+def virEventRemoveHandleImpl(handleID)
+end
+def virEventAddTimerImpl(interval, opaque)
+end
+def virEventUpdateTimerImpl(timer, timeout)
+end
+def virEventRemoveTimerImpl(timerID)
+end
+
+# proc callbacks
+virEventAddHandleProc = lambda {|fd, events, opaque|
+}
+virEventUpdateHandleProc = lambda {|watch, event|
+}
+virEventRemoveHandleProc = lambda {|handleID|
+}
+virEventAddTimerProc = lambda {|interval, opaque|
+}
+virEventUpdateTimerProc = lambda {|timer, timeout|
+}
+virEventRemoveTimerProc = lambda {|timerID|
+}
+
+expect_success(Libvirt, "all Symbol callbacks", "event_register_impl", :virEventAddHandleImpl, :virEventUpdateHandleImpl, :virEventRemoveHandleImpl, :virEventAddTimerImpl, :virEventUpdateTimerImpl, :virEventRemoveTimerImpl)
+expect_success(Libvirt, "unregister all callbacks", "event_register_impl", nil, nil, nil, nil, nil, nil)
+expect_success(Libvirt, "all Proc callbacks", "event_register_impl", virEventAddHandleProc, virEventUpdateHandleProc, virEventRemoveHandleProc, virEventAddTimerProc, virEventUpdateTimerProc, virEventRemoveTimerProc)
+expect_success(Libvirt, "unregister all callbacks", "event_register_impl")
+
+finish_tests
diff --git a/tests/test_secret.rb b/tests/test_secret.rb
new file mode 100644
index 0000000..aac2446
--- /dev/null
+++ b/tests/test_secret.rb
@@ -0,0 +1,89 @@
+#!/usr/bin/ruby
+
+# Test the secret methods the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+conn = Libvirt::open("qemu:///system")
+
+# TESTGROUP: secret.uuid
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(newsecret, "uuid", 1)
+
+expect_success(newsecret, "no args", "uuid") {|x| x == $SECRET_UUID}
+
+newsecret.undefine
+
+# TESTGROUP: secret.usagetype
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(newsecret, "usagetype", 1)
+
+expect_success(newsecret, "no args", "usagetype") {|x| x == Libvirt::Secret::USAGE_TYPE_VOLUME}
+
+newsecret.undefine
+
+# TESTGROUP: secret.usageid
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(newsecret, "usageid", 1)
+
+expect_success(newsecret, "no args", "usageid")
+
+newsecret.undefine
+
+# TESTGROUP: secret.xml_desc
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(newsecret, "xml_desc", 1, 2)
+expect_invalid_arg_type(newsecret, "xml_desc", "foo")
+
+expect_success(newsecret, "no args", "xml_desc")
+
+newsecret.undefine
+
+# TESTGROUP: secret.set_value
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(newsecret, "set_value", 1, 2, 3)
+expect_too_few_args(newsecret, "set_value")
+expect_invalid_arg_type(newsecret, "set_value", 1)
+expect_invalid_arg_type(newsecret, "set_value", "foo", "bar")
+
+expect_success(newsecret, "value arg", "set_value", "foo")
+
+newsecret.undefine
+
+# TESTGROUP: secret.get_value
+newsecret = conn.define_secret_xml($new_secret_xml)
+newsecret.set_value("foo")
+
+expect_too_many_args(newsecret, "get_value", 1, 2)
+expect_invalid_arg_type(newsecret, "get_value", 'foo')
+
+expect_success(newsecret, "no args", "get_value") {|x| x == 'foo'}
+
+newsecret.undefine
+
+# TESTGROUP: secret.undefine
+newsecret = conn.define_secret_xml($new_secret_xml)
+
+expect_too_many_args(newsecret, "undefine", 1)
+
+expect_success(newsecret, "no args", "undefine")
+
+# TESTGROUP: secret.free
+newsecret = conn.define_secret_xml($new_secret_xml)
+newsecret.undefine
+
+expect_too_many_args(newsecret, "free", 1)
+
+expect_success(newsecret, "no args", "free")
+
+conn.close
+
+finish_tests
diff --git a/tests/test_storage.rb b/tests/test_storage.rb
new file mode 100644
index 0000000..63fdcbe
--- /dev/null
+++ b/tests/test_storage.rb
@@ -0,0 +1,423 @@
+#!/usr/bin/ruby
+
+# Test the storage methods the bindings support
+
+$: << File.dirname(__FILE__)
+
+require 'libvirt'
+require 'test_utils.rb'
+
+conn = Libvirt::open("qemu:///system")
+
+begin
+  oldpool = conn.lookup_storage_pool_by_name("ruby-libvirt-tester")
+  oldpool.destroy
+  oldpool.undefine
+rescue
+  # in case we didn't find it, don't do anything
+end
+
+# test setup
+`rm -rf #{$POOL_PATH}; mkdir #{$POOL_PATH} ; echo $?`
+
+new_storage_vol_xml = <<EOF
+<volume>
+  <name>test.img</name>
+  <allocation>0</allocation>
+  <capacity unit="G">1</capacity>
+  <target>
+    <path>/tmp/ruby-libvirt-tester/test.img</path>
+  </target>
+</volume>
+EOF
+
+new_storage_vol_xml_2 = <<EOF
+<volume>
+  <name>test2.img</name>
+  <allocation>0</allocation>
+  <capacity unit="G">5</capacity>
+  <target>
+    <path>/tmp/ruby-libvirt-tester/test2.img</path>
+  </target>
+</volume>
+EOF
+
+# TESTGROUP: vol.pool
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "pool", 1)
+
+expect_success(newvol, "no args", "pool")
+
+newvol.delete
+
+newpool.destroy
+
+# TESTGROUP: pool.build
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "build", 1, 2)
+expect_invalid_arg_type(newpool, "build", 'foo')
+
+expect_success(newpool, "no args", "build")
+
+newpool.undefine
+
+# TESTGROUP: pool.undefine
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "undefine", 1)
+
+expect_success(newpool, "no args", "undefine")
+
+# TESTGROUP: pool.create
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "create", 1, 2)
+expect_invalid_arg_type(newpool, "create", 'foo')
+
+expect_success(newpool, "no args", "create")
+
+newpool.destroy
+newpool.undefine
+
+# TESTGROUP: pool.destroy
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "destroy", 1)
+
+expect_success(newpool, "no args", "destroy")
+
+# TESTGROUP: pool.delete
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "delete", 1, 2)
+expect_invalid_arg_type(newpool, "delete", 'foo')
+
+expect_success(newpool, "no args", "delete")
+
+`mkdir /tmp/ruby-libvirt-tester`
+
+newpool.undefine
+
+# TESTGROUP: pool.refresh
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "refresh", 1, 2)
+expect_invalid_arg_type(newpool, "refresh", 'foo')
+
+expect_success(newpool, "no args", "refresh")
+
+newpool.destroy
+
+# TESTGROUP: pool.name
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "name", 1)
+
+expect_success(newpool, "no args", "name") {|x| x == "ruby-libvirt-tester"}
+
+newpool.destroy
+
+# TESTGROUP: pool.uuid
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "uuid", 1)
+
+expect_success(newpool, "no args", "uuid") {|x| x == $POOL_UUID}
+
+newpool.destroy
+
+# TESTGROUP: pool.info
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "info", 1)
+
+expect_success(newpool, "no args", "info")
+
+newpool.destroy
+
+# TESTGROUP: pool.xml_desc
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "xml_desc", 1, 2)
+expect_invalid_arg_type(newpool, "xml_desc", "foo")
+
+expect_success(newpool, "no args", "xml_desc")
+
+newpool.destroy
+
+# TESTGROUP: pool.autostart?
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "autostart?", 1)
+
+expect_success(newpool, "no args", "autostart?") {|x| x == false}
+
+newpool.autostart = true
+
+expect_success(newpool, "no args", "autostart?") {|x| x == true}
+
+newpool.undefine
+
+# TESTGROUP: pool.autostart=
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "autostart=", 1, 2)
+expect_invalid_arg_type(newpool, "autostart=", 'foo')
+expect_invalid_arg_type(newpool, "autostart=", nil)
+expect_invalid_arg_type(newpool, "autostart=", 1234)
+
+expect_success(newpool, "no args", "autostart=", true)
+if not newpool.autostart?
+  puts_fail "pool.autostart= did not set autostart to true"
+else
+  puts_ok "pool.autostart= set autostart to true"
+end
+
+expect_success(newpool, "no args", "autostart=", false)
+if newpool.autostart?
+  puts_fail "pool.autostart= did not set autostart to false"
+else
+  puts_ok "pool.autostart= set autostart to false"
+end
+
+newpool.undefine
+
+# TESTGROUP: pool.num_of_volumes
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "num_of_volumes", 1)
+
+expect_success(newpool, "no args", "num_of_volumes") {|x| x == 0}
+
+newpool.destroy
+
+# TESTGROUP: pool.list_volumes
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "list_volumes", 1)
+
+expect_success(newpool, "no args", "list_volumes")
+
+newpool.destroy
+
+# TESTGROUP: pool.free
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+newpool.undefine
+expect_too_many_args(newpool, "free", 1)
+
+expect_success(newpool, "no args", "free")
+
+# TESTGROUP: pool.lookup_volume_by_name
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newpool, "lookup_volume_by_name", 1, 2)
+expect_too_few_args(newpool, "lookup_volume_by_name")
+expect_invalid_arg_type(newpool, "lookup_volume_by_name", 1);
+expect_invalid_arg_type(newpool, "lookup_volume_by_name", nil);
+expect_fail(newpool, Libvirt::RetrieveError, "non-existent name arg", "lookup_volume_by_name", "foobarbazsucker")
+
+expect_success(newpool, "name arg", "lookup_volume_by_name", "test.img")
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: pool.lookup_volume_by_key
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newpool, "lookup_volume_by_key", 1, 2)
+expect_too_few_args(newpool, "lookup_volume_by_key")
+expect_invalid_arg_type(newpool, "lookup_volume_by_key", 1);
+expect_invalid_arg_type(newpool, "lookup_volume_by_key", nil);
+expect_fail(newpool, Libvirt::RetrieveError, "non-existent key arg", "lookup_volume_by_key", "foobarbazsucker")
+
+expect_success(newpool, "name arg", "lookup_volume_by_key", newvol.key)
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: pool.lookup_volume_by_path
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newpool, "lookup_volume_by_path", 1, 2)
+expect_too_few_args(newpool, "lookup_volume_by_path")
+expect_invalid_arg_type(newpool, "lookup_volume_by_path", 1);
+expect_invalid_arg_type(newpool, "lookup_volume_by_path", nil);
+expect_fail(newpool, Libvirt::RetrieveError, "non-existent path arg", "lookup_volume_by_path", "foobarbazsucker")
+
+expect_success(newpool, "name arg", "lookup_volume_by_path", newvol.path)
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: vol.name
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "name", 1)
+
+expect_success(newvol, "no args", "name")
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: vol.key
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "key", 1)
+
+expect_success(newvol, "no args", "key")
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: pool.create_volume_xml
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "create_volume_xml", new_storage_vol_xml, 0, 1)
+expect_too_few_args(newpool, "create_volume_xml")
+expect_invalid_arg_type(newpool, "create_volume_xml", nil)
+expect_invalid_arg_type(newpool, "create_volume_xml", 1)
+expect_invalid_arg_type(newpool, "create_volume_xml", new_storage_vol_xml, "foo")
+expect_fail(newpool, Libvirt::Error, "invalid xml", "create_volume_xml", "hello")
+
+expect_success(newpool, "storage volume XML", "create_volume_xml", new_storage_vol_xml)
+
+expect_fail(newpool, Libvirt::Error, "already existing domain", "create_volume_xml", new_storage_vol_xml)
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: pool.create_volume_xml_from
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newpool, "create_volume_xml_from", new_storage_vol_xml_2, 0, 1, 2)
+expect_too_few_args(newpool, "create_volume_xml_from")
+expect_invalid_arg_type(newpool, "create_volume_xml_from", 1, 2)
+expect_invalid_arg_type(newpool, "create_volume_xml_from", "foo", 2)
+expect_invalid_arg_type(newpool, "create_volume_xml_from", "foo", newvol, "bar")
+expect_fail(newpool, Libvirt::Error, "invalid xml", "create_volume_xml_from", "hello", newvol)
+
+newvol2 = expect_success(newpool, "storage volume XML", "create_volume_xml_from", new_storage_vol_xml_2, newvol)
+
+expect_fail(newpool, Libvirt::Error, "already existing domain", "create_volume_xml_from", new_storage_vol_xml_2, newvol)
+
+newvol2.delete
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: pool.active?
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+
+expect_too_many_args(newpool, "active?", 1)
+
+expect_success(newpool, "no args", "active?") {|x| x == true}
+
+newpool.destroy
+
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_success(newpool, "no args", "active?") {|x| x == false}
+
+newpool.create
+
+expect_success(newpool, "no args", "active?") {|x| x == true}
+
+newpool.destroy
+newpool.undefine
+
+# TESTGROUP: pool.persistent?
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+sleep 1
+
+expect_too_many_args(newpool, "persistent?", 1)
+
+expect_success(newpool, "no args", "persistent?") {|x| x == false}
+
+newpool.destroy
+
+newpool = conn.define_storage_pool_xml($new_storage_pool_xml)
+
+expect_success(newpool, "no args", "persistent?") {|x| x == true}
+
+newpool.undefine
+
+# TESTGROUP: vol.delete
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "delete", 1, 2)
+expect_invalid_arg_type(newvol, "delete", 'foo')
+
+expect_success(newvol, "no args", "delete")
+
+newpool.destroy
+
+# TESTGROUP: vol.wipe
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "wipe", 1, 2)
+expect_invalid_arg_type(newvol, "wipe", 'foo')
+
+expect_success(newvol, "no args", "wipe")
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: vol.info
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "info", 1)
+
+expect_success(newvol, "no args", "info")
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: vol.xml_desc
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "xml_desc", 1, 2)
+expect_invalid_arg_type(newvol, "xml_desc", "foo")
+
+expect_success(newvol, "no args", "xml_desc")
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: vol.path
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+
+expect_too_many_args(newvol, "path", 1)
+
+expect_success(newvol, "no args", "path")
+
+newvol.delete
+newpool.destroy
+
+# TESTGROUP: vol.free
+newpool = conn.create_storage_pool_xml($new_storage_pool_xml)
+newvol = newpool.create_volume_xml(new_storage_vol_xml)
+newvol.delete
+
+expect_too_many_args(newvol, "free", 1)
+
+expect_success(newvol, "no args", "free")
+
+newpool.destroy
+
+conn.close
+
+finish_tests
diff --git a/tests/test_utils.rb b/tests/test_utils.rb
new file mode 100644
index 0000000..cc0c856
--- /dev/null
+++ b/tests/test_utils.rb
@@ -0,0 +1,180 @@
+$FAIL = 0
+$SUCCESS = 0
+$SKIPPED = 0
+
+$GUEST_DISK = '/var/lib/libvirt/images/ruby-libvirt-tester.qcow2'
+$GUEST_UUID = "93a5c045-6457-2c09-e56f-927cdf34e17a"
+
+# XML data for later tests
+$new_dom_xml = <<EOF
+<domain type='kvm'>
+  <name>ruby-libvirt-tester</name>
+  <uuid>#{$GUEST_UUID}</uuid>
+  <memory>1048576</memory>
+  <currentMemory>1048576</currentMemory>
+  <vcpu>2</vcpu>
+  <os>
+    <type arch='x86_64'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <acpi/>
+    <apic/>
+    <pae/>
+  </features>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='qcow2'/>
+      <source file='#{$GUEST_DISK}'/>
+      <target dev='vda' bus='virtio'/>
+    </disk>
+    <interface type='bridge'>
+      <mac address='52:54:00:60:3c:95'/>
+      <source bridge='virbr0'/>
+      <model type='virtio'/>
+      <target dev='rl556'/>
+    </interface>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <console type='pty'>
+      <target port='0'/>
+    </console>
+    <input type='mouse' bus='ps2'/>
+    <graphics type='vnc' port='-1' autoport='yes' keymap='en-us'/>
+    <video>
+      <model type='cirrus' vram='9216' heads='1'/>
+    </video>
+  </devices>
+</domain>
+EOF
+
+# qemu command-line that roughly corresponds to the above XML
+$qemu_cmd_line = "/usr/bin/qemu-kvm -S -M pc-0.13 -enable-kvm -m 1024 -smp 1,sockets=1,cores=1,threads=1 -name ruby-libvirt-tester -uuid #{$GUEST_UUID} -nodefconfig -nodefaults -chardev socket,id=monitor,path=/var/lib/libvirt/qemu/ruby-libvirt-tester.monitor,server,nowait -mon chardev=monitor,mode=readline -rtc base=utc -boot c -chardev pty,id=serial0 -device isa-serial,chardev=serial0 -usb -vnc 127.0.0.1:0 -k en-us -vga cirrus -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5"
+
+$new_interface_xml = <<EOF
+<interface type="bridge" name="ruby-libvirt-tester">
+  <start mode="onboot"/>
+  <bridge delay="0">
+  </bridge>
+</interface>
+EOF
+
+$NETWORK_UUID = "04068860-d9a2-47c5-bc9d-9e047ae901da"
+$new_net_xml = <<EOF
+<network>
+  <name>ruby-libvirt-tester</name>
+  <uuid>#{$NETWORK_UUID}</uuid>
+  <forward mode='nat'/>
+  <bridge name='rubybr0' stp='on' delay='0' />
+  <ip address='192.168.134.1' netmask='255.255.255.0'>
+    <dhcp>
+      <range start='192.168.134.2' end='192.168.134.254' />
+    </dhcp>
+  </ip>
+</network>
+EOF
+
+$NWFILTER_UUID = "bd339530-134c-6d07-441a-17fb90dad807"
+$new_nwfilter_xml = <<EOF
+<filter name='ruby-libvirt-tester' chain='ipv4'>
+  <uuid>#{$NWFILTER_UUID}</uuid>
+  <rule action='accept' direction='out' priority='100'>
+    <ip srcipaddr='0.0.0.0' dstipaddr='255.255.255.255' protocol='tcp' srcportstart='63000' dstportstart='62000'/>
+  </rule>
+  <rule action='accept' direction='in' priority='100'>
+    <ip protocol='tcp' srcportstart='63000' dstportstart='62000'/>
+  </rule>
+</filter>
+EOF
+
+$SECRET_UUID = "bd339530-134c-6d07-4410-17fb90dad805"
+$new_secret_xml = <<EOF
+<secret ephemeral='no' private='no'>
+  <description>test secret</description>
+  <uuid>#{$SECRET_UUID}</uuid>
+  <usage type='volume'>
+    <volume>/var/lib/libvirt/images/mail.img</volume>
+  </usage>
+</secret>
+EOF
+
+$POOL_UUID = "33a5c045-645a-2c00-e56b-927cdf34e17a"
+$POOL_PATH = "/var/lib/libvirt/images/ruby-libvirt-tester"
+$new_storage_pool_xml = <<EOF
+<pool type="dir">
+  <name>ruby-libvirt-tester</name>
+  <uuid>#{$POOL_UUID}</uuid>
+  <target>
+    <path>#{$POOL_PATH}</path>
+  </target>
+</pool>
+EOF
+
+def expect_success(object, msg, func, *args)
+  begin
+    x = object.send(func, *args)
+    if block_given?
+      res = yield x
+      if not res
+        # FIXME: generate a proper error here
+        raise "Failed"
+      end
+    end
+    puts_ok "#{func} #{msg} succeeded"
+    x
+  rescue NoMethodError
+    puts_skipped "#{func} does not exist"
+  rescue => e
+    puts_fail "#{func} #{msg} expected to succeed, threw #{e.class.to_s}: #{e.to_s}"
+  end
+end
+
+def expect_fail(object, errtype, errmsg, func, *args)
+  begin
+    object.send(func, *args)
+  rescue NoMethodError
+    puts_skipped "#{func} does not exist"
+  rescue errtype => e
+    puts_ok "#{func} #{errmsg} threw #{errtype.to_s}"
+  rescue => e
+    puts_fail "#{func} #{errmsg} expected to throw #{errtype.to_s}, but instead threw #{e.class.to_s}: #{e.to_s}"
+  else
+    puts_fail "#{func} #{errmsg} expected to throw #{errtype.to_s}, but threw nothing"
+  end
+end
+
+def expect_too_many_args(object, func, *args)
+  expect_fail(object, ArgumentError, "too many args", func, *args)
+end
+
+def expect_too_few_args(object, func, *args)
+  expect_fail(object, ArgumentError, "too few args", func, *args)
+end
+
+def expect_invalid_arg_type(object, func, *args)
+  expect_fail(object, TypeError, "invalid arg type", func, *args)
+end
+
+def puts_ok(str)
+  puts "OK: " + str
+  $SUCCESS = $SUCCESS + 1
+end
+
+def puts_fail(str)
+  puts "FAIL: " + str
+  $FAIL = $FAIL + 1
+end
+
+def puts_skipped(str)
+  puts "SKIPPED: " + str
+  $SKIPPED = $SKIPPED + 1
+end
+
+def finish_tests
+  puts "Successfully finished #{$SUCCESS} tests, failed #{$FAIL} tests, skipped #{$SKIPPED} tests"
+end

-- 
libvirt ruby bindinds packaging



More information about the Pkg-libvirt-commits mailing list