Don't bother checking return from virInitialize.
[ocaml-libvirt.git] / libvirt / libvirt_c_oneoffs.c
index c51aad7..5d82194 100644 (file)
@@ -32,7 +32,7 @@ ocaml_libvirt_get_version (value driverv, value unit)
 
   typeVer_ptr = driver ? &typeVer : NULL;
   NONBLOCKING (r = virGetVersion (&libVer, driver, typeVer_ptr));
-  CHECK_ERROR (r == -1, NULL, "virGetVersion");
+  CHECK_ERROR (r == -1, "virGetVersion");
 
   rv = caml_alloc_tuple (2);
   Store_field (rv, 0, Val_int (libVer));
@@ -53,7 +53,7 @@ ocaml_libvirt_connect_open (value namev, value unit)
   virConnectPtr conn;
 
   NONBLOCKING (conn = virConnectOpen (name));
-  CHECK_ERROR (!conn, NULL, "virConnectOpen");
+  CHECK_ERROR (!conn, "virConnectOpen");
 
   rv = Val_connect (conn);
 
@@ -69,7 +69,7 @@ ocaml_libvirt_connect_open_readonly (value namev, value unit)
   virConnectPtr conn;
 
   NONBLOCKING (conn = virConnectOpenReadOnly (name));
-  CHECK_ERROR (!conn, NULL, "virConnectOpen");
+  CHECK_ERROR (!conn, "virConnectOpen");
 
   rv = Val_connect (conn);
 
@@ -85,7 +85,7 @@ ocaml_libvirt_connect_get_version (value connv)
   int r;
 
   NONBLOCKING (r = virConnectGetVersion (conn, &hvVer));
-  CHECK_ERROR (r == -1, conn, "virConnectGetVersion");
+  CHECK_ERROR (r == -1, "virConnectGetVersion");
 
   CAMLreturn (Val_int (hvVer));
 }
@@ -99,7 +99,7 @@ ocaml_libvirt_connect_get_max_vcpus (value connv, value typev)
   int r;
 
   NONBLOCKING (r = virConnectGetMaxVcpus (conn, type));
-  CHECK_ERROR (r == -1, conn, "virConnectGetMaxVcpus");
+  CHECK_ERROR (r == -1, "virConnectGetMaxVcpus");
 
   CAMLreturn (Val_int (r));
 }
@@ -114,7 +114,7 @@ ocaml_libvirt_connect_get_node_info (value connv)
   int r;
 
   NONBLOCKING (r = virNodeGetInfo (conn, &info));
-  CHECK_ERROR (r == -1, conn, "virNodeGetInfo");
+  CHECK_ERROR (r == -1, "virNodeGetInfo");
 
   rv = caml_alloc (8, 0);
   v = caml_copy_string (info.model); Store_field (rv, 0, v);
@@ -138,9 +138,9 @@ ocaml_libvirt_connect_node_get_free_memory (value connv)
   unsigned long long r;
 
   NONBLOCKING (r = virNodeGetFreeMemory (conn));
-  CHECK_ERROR (r == 0, conn, "virNodeGetFreeMemory");
+  CHECK_ERROR (r == 0, "virNodeGetFreeMemory");
 
-  rv = caml_copy_int64 ((int64) r);
+  rv = caml_copy_int64 ((int64_t) r);
   CAMLreturn (rv);
 }
 
@@ -157,11 +157,11 @@ ocaml_libvirt_connect_node_get_cells_free_memory (value connv,
   unsigned long long freemems[max];
 
   NONBLOCKING (r = virNodeGetCellsFreeMemory (conn, freemems, start, max));
-  CHECK_ERROR (r == -1, conn, "virNodeGetCellsFreeMemory");
+  CHECK_ERROR (r == -1, "virNodeGetCellsFreeMemory");
 
   rv = caml_alloc (r, 0);
   for (i = 0; i < r; ++i) {
-    iv = caml_copy_int64 ((int64) freemems[i]);
+    iv = caml_copy_int64 ((int64_t) freemems[i]);
     Store_field (rv, i, iv);
   }
 
@@ -179,7 +179,7 @@ ocaml_libvirt_connect_set_keep_alive(value connv,
   int r;
 
   NONBLOCKING(r = virConnectSetKeepAlive(conn, interval, count));
-  CHECK_ERROR (r == -1, conn, "virConnectSetKeepAlive");
+  CHECK_ERROR (r == -1, "virConnectSetKeepAlive");
 
   CAMLreturn(Val_unit);
 }
@@ -190,7 +190,6 @@ ocaml_libvirt_domain_get_id (value domv)
 {
   CAMLparam1 (domv);
   virDomainPtr dom = Domain_val (domv);
-  /*virConnectPtr conn = Connect_domv (domv);*/
   unsigned int r;
 
   NONBLOCKING (r = virDomainGetID (dom));
@@ -208,11 +207,10 @@ ocaml_libvirt_domain_get_max_memory (value domv)
   CAMLparam1 (domv);
   CAMLlocal1 (rv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   unsigned long r;
 
   NONBLOCKING (r = virDomainGetMaxMemory (dom));
-  CHECK_ERROR (r == 0 /* [sic] */, conn, "virDomainGetMaxMemory");
+  CHECK_ERROR (r == 0 /* [sic] */, "virDomainGetMaxMemory");
 
   rv = caml_copy_int64 (r);
   CAMLreturn (rv);
@@ -223,12 +221,11 @@ ocaml_libvirt_domain_set_max_memory (value domv, value memv)
 {
   CAMLparam2 (domv, memv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   unsigned long mem = Int64_val (memv);
   int r;
 
   NONBLOCKING (r = virDomainSetMaxMemory (dom, mem));
-  CHECK_ERROR (r == -1, conn, "virDomainSetMaxMemory");
+  CHECK_ERROR (r == -1, "virDomainSetMaxMemory");
 
   CAMLreturn (Val_unit);
 }
@@ -238,12 +235,11 @@ ocaml_libvirt_domain_set_memory (value domv, value memv)
 {
   CAMLparam2 (domv, memv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   unsigned long mem = Int64_val (memv);
   int r;
 
   NONBLOCKING (r = virDomainSetMemory (dom, mem));
-  CHECK_ERROR (r == -1, conn, "virDomainSetMemory");
+  CHECK_ERROR (r == -1, "virDomainSetMemory");
 
   CAMLreturn (Val_unit);
 }
@@ -254,12 +250,11 @@ ocaml_libvirt_domain_get_info (value domv)
   CAMLparam1 (domv);
   CAMLlocal2 (rv, v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   virDomainInfo info;
   int r;
 
   NONBLOCKING (r = virDomainGetInfo (dom, &info));
-  CHECK_ERROR (r == -1, conn, "virDomainGetInfo");
+  CHECK_ERROR (r == -1, "virDomainGetInfo");
 
   rv = caml_alloc (5, 0);
   Store_field (rv, 0, Val_int (info.state)); // These flags are compatible.
@@ -277,12 +272,11 @@ ocaml_libvirt_domain_get_scheduler_type (value domv)
   CAMLparam1 (domv);
   CAMLlocal2 (rv, strv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   char *r;
   int nparams;
 
   NONBLOCKING (r = virDomainGetSchedulerType (dom, &nparams));
-  CHECK_ERROR (!r, conn, "virDomainGetSchedulerType");
+  CHECK_ERROR (!r, "virDomainGetSchedulerType");
 
   rv = caml_alloc_tuple (2);
   strv = caml_copy_string (r); Store_field (rv, 0, strv);
@@ -297,13 +291,12 @@ ocaml_libvirt_domain_get_scheduler_parameters (value domv, value nparamsv)
   CAMLparam2 (domv, nparamsv);
   CAMLlocal4 (rv, v, v2, v3);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int nparams = Int_val (nparamsv);
   virSchedParameter params[nparams];
   int r, i;
 
   NONBLOCKING (r = virDomainGetSchedulerParameters (dom, params, &nparams));
-  CHECK_ERROR (r == -1, conn, "virDomainGetSchedulerParameters");
+  CHECK_ERROR (r == -1, "virDomainGetSchedulerParameters");
 
   rv = caml_alloc (nparams, 0);
   for (i = 0; i < nparams; ++i) {
@@ -348,7 +341,6 @@ ocaml_libvirt_domain_set_scheduler_parameters (value domv, value paramsv)
   CAMLparam2 (domv, paramsv);
   CAMLlocal1 (v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int nparams = Wosize_val (paramsv);
   virSchedParameter params[nparams];
   int r, i;
@@ -391,7 +383,7 @@ ocaml_libvirt_domain_set_scheduler_parameters (value domv, value paramsv)
   }
 
   NONBLOCKING (r = virDomainSetSchedulerParameters (dom, params, nparams));
-  CHECK_ERROR (r == -1, conn, "virDomainSetSchedulerParameters");
+  CHECK_ERROR (r == -1, "virDomainSetSchedulerParameters");
 
   CAMLreturn (Val_unit);
 }
@@ -401,11 +393,10 @@ ocaml_libvirt_domain_set_vcpus (value domv, value nvcpusv)
 {
   CAMLparam2 (domv, nvcpusv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int r, nvcpus = Int_val (nvcpusv);
 
   NONBLOCKING (r = virDomainSetVcpus (dom, nvcpus));
-  CHECK_ERROR (r == -1, conn, "virDomainSetVcpus");
+  CHECK_ERROR (r == -1, "virDomainSetVcpus");
 
   CAMLreturn (Val_unit);
 }
@@ -415,14 +406,13 @@ ocaml_libvirt_domain_pin_vcpu (value domv, value vcpuv, value cpumapv)
 {
   CAMLparam3 (domv, vcpuv, cpumapv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int maplen = caml_string_length (cpumapv);
   unsigned char *cpumap = (unsigned char *) String_val (cpumapv);
   int vcpu = Int_val (vcpuv);
   int r;
 
   NONBLOCKING (r = virDomainPinVcpu (dom, vcpu, cpumap, maplen));
-  CHECK_ERROR (r == -1, conn, "virDomainPinVcpu");
+  CHECK_ERROR (r == -1, "virDomainPinVcpu");
 
   CAMLreturn (Val_unit);
 }
@@ -433,7 +423,6 @@ ocaml_libvirt_domain_get_vcpus (value domv, value maxinfov, value maplenv)
   CAMLparam3 (domv, maxinfov, maplenv);
   CAMLlocal5 (rv, infov, strv, v, v2);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int maxinfo = Int_val (maxinfov);
   int maplen = Int_val (maplenv);
   virVcpuInfo info[maxinfo];
@@ -444,7 +433,7 @@ ocaml_libvirt_domain_get_vcpus (value domv, value maxinfov, value maplenv)
   memset (cpumaps, 0, maxinfo * maplen);
 
   NONBLOCKING (r = virDomainGetVcpus (dom, info, maxinfo, cpumaps, maplen));
-  CHECK_ERROR (r == -1, conn, "virDomainPinVcpu");
+  CHECK_ERROR (r == -1, "virDomainPinVcpu");
 
   /* Copy the virVcpuInfo structures. */
   infov = caml_alloc (maxinfo, 0);
@@ -476,18 +465,17 @@ ocaml_libvirt_domain_get_cpu_stats (value domv)
   CAMLlocal5 (cpustats, param_head, param_node, typed_param, typed_param_value);
   CAMLlocal1 (v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   virTypedParameterPtr params;
   int r, cpu, ncpus, nparams, i, j, pos;
   int nr_pcpus;
 
   /* get number of pcpus */
   NONBLOCKING (nr_pcpus = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0));
-  CHECK_ERROR (nr_pcpus < 0, conn, "virDomainGetCPUStats");
+  CHECK_ERROR (nr_pcpus < 0, "virDomainGetCPUStats");
 
   /* get percpu information */
   NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0));
-  CHECK_ERROR (nparams < 0, conn, "virDomainGetCPUStats");
+  CHECK_ERROR (nparams < 0, "virDomainGetCPUStats");
 
   if ((params = malloc(sizeof(*params) * nparams * 128)) == NULL)
     caml_failwith ("virDomainGetCPUStats: malloc");
@@ -498,7 +486,7 @@ ocaml_libvirt_domain_get_cpu_stats (value domv)
     ncpus = nr_pcpus - cpu > 128 ? 128 : nr_pcpus - cpu;
 
     NONBLOCKING (r = virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 0));
-    CHECK_ERROR (r < 0, conn, "virDomainGetCPUStats");
+    CHECK_ERROR (r < 0, "virDomainGetCPUStats");
 
     for (i = 0; i < ncpus; i++) {
       /* list of typed_param: single linked list of param_nodes */
@@ -579,7 +567,6 @@ ocaml_libvirt_domain_migrate_native (value domv, value dconnv, value flagsv, val
   CAMLxparam2 (optbandwidthv, unitv);
   CAMLlocal2 (flagv, rv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   virConnectPtr dconn = Connect_val (dconnv);
   int flags = 0;
   const char *dname = Optstring_val (optdnamev);
@@ -601,7 +588,7 @@ ocaml_libvirt_domain_migrate_native (value domv, value dconnv, value flagsv, val
     bandwidth = Int_val (Field (optbandwidthv, 0));
 
   NONBLOCKING (r = virDomainMigrate (dom, dconn, flags, dname, uri, bandwidth));
-  CHECK_ERROR (!r, conn, "virDomainMigrate");
+  CHECK_ERROR (!r, "virDomainMigrate");
 
   rv = Val_domain (r, dconnv);
 
@@ -622,13 +609,12 @@ ocaml_libvirt_domain_block_stats (value domv, value pathv)
   CAMLparam2 (domv, pathv);
   CAMLlocal2 (rv,v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   char *path = String_val (pathv);
   struct _virDomainBlockStats stats;
   int r;
 
   NONBLOCKING (r = virDomainBlockStats (dom, path, &stats, sizeof stats));
-  CHECK_ERROR (r == -1, conn, "virDomainBlockStats");
+  CHECK_ERROR (r == -1, "virDomainBlockStats");
 
   rv = caml_alloc (5, 0);
   v = caml_copy_int64 (stats.rd_req); Store_field (rv, 0, v);
@@ -646,13 +632,12 @@ ocaml_libvirt_domain_interface_stats (value domv, value pathv)
   CAMLparam2 (domv, pathv);
   CAMLlocal2 (rv,v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   char *path = String_val (pathv);
   struct _virDomainInterfaceStats stats;
   int r;
 
   NONBLOCKING (r = virDomainInterfaceStats (dom, path, &stats, sizeof stats));
-  CHECK_ERROR (r == -1, conn, "virDomainInterfaceStats");
+  CHECK_ERROR (r == -1, "virDomainInterfaceStats");
 
   rv = caml_alloc (8, 0);
   v = caml_copy_int64 (stats.rx_bytes); Store_field (rv, 0, v);
@@ -673,7 +658,6 @@ ocaml_libvirt_domain_block_peek_native (value domv, value pathv, value offsetv,
   CAMLparam5 (domv, pathv, offsetv, sizev, bufferv);
   CAMLxparam1 (boffv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   const char *path = String_val (pathv);
   unsigned long long offset = Int64_val (offsetv);
   size_t size = Int_val (sizev);
@@ -687,7 +671,7 @@ ocaml_libvirt_domain_block_peek_native (value domv, value pathv, value offsetv,
 
   /* NB. not NONBLOCKING because buffer might move (XXX) */
   r = virDomainBlockPeek (dom, path, offset, size, buffer+boff, 0);
-  CHECK_ERROR (r == -1, conn, "virDomainBlockPeek");
+  CHECK_ERROR (r == -1, "virDomainBlockPeek");
 
   CAMLreturn (Val_unit);
 }
@@ -706,7 +690,6 @@ ocaml_libvirt_domain_memory_peek_native (value domv, value flagsv, value offsetv
   CAMLxparam1 (boffv);
   CAMLlocal1 (flagv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int flags = 0;
   unsigned long long offset = Int64_val (offsetv);
   size_t size = Int_val (sizev);
@@ -728,7 +711,7 @@ ocaml_libvirt_domain_memory_peek_native (value domv, value flagsv, value offsetv
 
   /* NB. not NONBLOCKING because buffer might move (XXX) */
   r = virDomainMemoryPeek (dom, offset, size, buffer+boff, flags);
-  CHECK_ERROR (r == -1, conn, "virDomainMemoryPeek");
+  CHECK_ERROR (r == -1, "virDomainMemoryPeek");
 
   CAMLreturn (Val_unit);
 }
@@ -740,18 +723,426 @@ ocaml_libvirt_domain_memory_peek_bytecode (value *argv, int argn)
                                                   argv[3], argv[4], argv[5]);
 }
 
+/*----------------------------------------------------------------------*/
+
+/* Domain events */
+
+CAMLprim value
+ocaml_libvirt_event_register_default_impl (value unitv)
+{
+  CAMLparam1 (unitv);
+
+  /* arg is of type unit = void */
+  int r;
+
+  NONBLOCKING (r = virEventRegisterDefaultImpl ());
+  /* must be called before connection, therefore we can't use CHECK_ERROR */
+  if (r == -1) caml_failwith("virEventRegisterDefaultImpl");
+
+  CAMLreturn (Val_unit);
+}
+
+CAMLprim value
+ocaml_libvirt_event_run_default_impl (value unitv)
+{
+  CAMLparam1 (unitv);
+
+  /* arg is of type unit = void */
+  int r;
+
+  NONBLOCKING (r = virEventRunDefaultImpl ());
+  if (r == -1) caml_failwith("virEventRunDefaultImpl");
+
+  CAMLreturn (Val_unit);
+}
+
+/* We register a single C callback function for every distinct
+   callback signature. We encode the signature itself in the function
+   name and also in the name of the assocated OCaml callback
+   e.g.:
+      a C function called
+         i_i64_s_callback(virConnectPtr conn,
+                         virDomainPtr dom,
+                         int x,
+                         long y,
+                         char *z,
+                         void *opaque)
+      would correspond to an OCaml callback
+         Libvirt.i_i64_s_callback :
+          int64 -> [`R] Domain.t -> int -> int64 -> string option -> unit
+      where the initial int64 is a unique ID used by the OCaml to
+      dispatch to the specific OCaml closure and stored by libvirt
+      as the "opaque" data. */
+
+/* Every one of the callbacks starts with a DOMAIN_CALLBACK_BEGIN(NAME)
+   where NAME is the string name of the OCaml callback registered
+   in libvirt.ml. */
+#define DOMAIN_CALLBACK_BEGIN(NAME)                              \
+  value connv, domv, callback_id, result;                        \
+  connv = domv = callback_id = result = Val_int(0);              \
+  static value *callback = NULL;                                 \
+  caml_leave_blocking_section();                                 \
+  if (callback == NULL)                                          \
+    callback = caml_named_value(NAME);                           \
+  if (callback == NULL)                                          \
+    abort(); /* C code out of sync with OCaml code */            \
+  if ((virDomainRef(dom) == -1) || (virConnectRef(conn) == -1))  \
+    abort(); /* should never happen in practice? */              \
+                                                                 \
+  Begin_roots4(connv, domv, callback_id, result);                \
+  connv = Val_connect(conn);                                     \
+  domv = Val_domain(dom, connv);                                 \
+  callback_id = caml_copy_int64(*(long *)opaque);
+
+/* Every one of the callbacks ends with a CALLBACK_END */
+#define DOMAIN_CALLBACK_END                                      \
+  (void) caml_callback3(*callback, callback_id, domv, result);   \
+  End_roots();                                                   \
+  caml_enter_blocking_section();
+
+
+static void
+i_i_callback(virConnectPtr conn,
+            virDomainPtr dom,
+            int x,
+            int y,
+            void * opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.i_i_callback")
+  result = caml_alloc_tuple(2);
+  Store_field(result, 0, Val_int(x));
+  Store_field(result, 1, Val_int(y));
+  DOMAIN_CALLBACK_END
+}
+
+static void
+u_callback(virConnectPtr conn,
+          virDomainPtr dom,
+          void *opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.u_callback")
+  result = Val_int(0); /* () */
+  DOMAIN_CALLBACK_END
+}
+
+static void
+i64_callback(virConnectPtr conn,
+            virDomainPtr dom,
+            long long int64,
+            void *opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.i64_callback")
+  result = caml_copy_int64(int64);
+  DOMAIN_CALLBACK_END
+}
+
+static void
+i_callback(virConnectPtr conn,
+          virDomainPtr dom,
+          int x,
+          void *opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.i_callback")
+  result = Val_int(x);
+  DOMAIN_CALLBACK_END
+}
+
+static void
+s_i_callback(virConnectPtr conn,
+            virDomainPtr dom,
+            char *x,
+            int y,
+            void * opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.s_i_callback")
+  result = caml_alloc_tuple(2);
+  Store_field(result, 0, 
+             Val_opt(x, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 1, Val_int(y));
+  DOMAIN_CALLBACK_END
+}
+
+static void
+s_i_i_callback(virConnectPtr conn,
+              virDomainPtr dom,
+              char *x,
+              int y,
+              int z,
+              void * opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.s_i_i_callback")
+  result = caml_alloc_tuple(3);
+  Store_field(result, 0, 
+             Val_opt(x, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 1, Val_int(y));
+  Store_field(result, 2, Val_int(z));
+  DOMAIN_CALLBACK_END
+}
+
+static void
+s_s_i_callback(virConnectPtr conn,
+              virDomainPtr dom,
+              char *x,
+              char *y,
+              int z,
+              void *opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.s_s_i_callback")
+  result = caml_alloc_tuple(3);
+  Store_field(result, 0, 
+             Val_opt(x, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 1,
+             Val_opt(y, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 2, Val_int(z));
+  DOMAIN_CALLBACK_END
+}
+
+static void
+s_s_i_s_callback(virConnectPtr conn,
+                virDomainPtr dom,
+                char *x,
+                char *y,
+                int z,
+                char *a,
+                void *opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.s_s_i_s_callback")
+  result = caml_alloc_tuple(4);
+  Store_field(result, 0, 
+             Val_opt(x, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 1,
+             Val_opt(y, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 2, Val_int(z));
+  Store_field(result, 3,
+             Val_opt(a, (Val_ptr_t) caml_copy_string));
+  DOMAIN_CALLBACK_END
+}
+
+static void
+s_s_s_i_callback(virConnectPtr conn,
+                virDomainPtr dom,
+                char * x,
+                char * y,
+                char * z,
+                int a,
+                void * opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.s_s_s_i_callback")
+  result = caml_alloc_tuple(4);
+  Store_field(result, 0,
+             Val_opt(x, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 1,
+              Val_opt(y, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 2,
+              Val_opt(z, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 3, Val_int(a));
+  DOMAIN_CALLBACK_END
+}
+
+static value
+Val_event_graphics_address(virDomainEventGraphicsAddressPtr x)
+{
+  CAMLparam0 ();
+  CAMLlocal1(result);
+  result = caml_alloc_tuple(3);
+  Store_field(result, 0, Val_int(x->family));
+  Store_field(result, 1,
+             Val_opt((void *) x->node, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 2,
+             Val_opt((void *) x->service, (Val_ptr_t) caml_copy_string));
+  CAMLreturn(result);
+}
+
+static value
+Val_event_graphics_subject_identity(virDomainEventGraphicsSubjectIdentityPtr x)
+{
+  CAMLparam0 ();
+  CAMLlocal1(result);
+  result = caml_alloc_tuple(2);
+  Store_field(result, 0,
+             Val_opt((void *) x->type, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 1,
+             Val_opt((void *) x->name, (Val_ptr_t) caml_copy_string));
+  CAMLreturn(result);
+
+}
+
+static value
+Val_event_graphics_subject(virDomainEventGraphicsSubjectPtr x)
+{
+  CAMLparam0 ();
+  CAMLlocal1(result);
+  int i;
+  result = caml_alloc_tuple(x->nidentity);
+  for (i = 0; i < x->nidentity; i++ )
+    Store_field(result, i,
+               Val_event_graphics_subject_identity(x->identities + i));
+  CAMLreturn(result);
+}
+
+static void
+i_ga_ga_s_gs_callback(virConnectPtr conn,
+                     virDomainPtr dom,
+                     int i1,
+                     virDomainEventGraphicsAddressPtr ga1,
+                     virDomainEventGraphicsAddressPtr ga2,
+                     char *s1,
+                     virDomainEventGraphicsSubjectPtr gs1,
+                     void * opaque)
+{
+  DOMAIN_CALLBACK_BEGIN("Libvirt.i_ga_ga_s_gs_callback")
+  result = caml_alloc_tuple(5);
+  Store_field(result, 0, Val_int(i1));
+  Store_field(result, 1, Val_event_graphics_address(ga1));
+  Store_field(result, 2, Val_event_graphics_address(ga2)); 
+  Store_field(result, 3,
+             Val_opt(s1, (Val_ptr_t) caml_copy_string));
+  Store_field(result, 4, Val_event_graphics_subject(gs1));
+  DOMAIN_CALLBACK_END
+}
+
+static void
+timeout_callback(int timer, void *opaque)
+{
+  value callback_id, result;
+  callback_id = result = Val_int(0);
+  static value *callback = NULL;
+  caml_leave_blocking_section();
+  if (callback == NULL)
+    callback = caml_named_value("Libvirt.timeout_callback");
+  if (callback == NULL)
+    abort(); /* C code out of sync with OCaml code */
+
+  Begin_roots2(callback_id, result);
+  callback_id = caml_copy_int64(*(long *)opaque);
+
+  (void)caml_callback_exn(*callback, callback_id);
+  End_roots();
+  caml_enter_blocking_section();
+}
+
+CAMLprim value
+ocaml_libvirt_event_add_timeout (value connv, value ms, value callback_id)
+{
+  CAMLparam3 (connv, ms, callback_id);
+  void *opaque;
+  virFreeCallback freecb = free;
+  virEventTimeoutCallback cb = timeout_callback;
+
+  int r;
+
+  /* Store the int64 callback_id as the opaque data so the OCaml
+     callback can demultiplex to the correct OCaml handler. */
+  if ((opaque = malloc(sizeof(long))) == NULL)
+    caml_failwith ("virEventAddTimeout: malloc");
+  *((long*)opaque) = Int64_val(callback_id);
+  NONBLOCKING(r = virEventAddTimeout(Int_val(ms), cb, opaque, freecb));
+  CHECK_ERROR(r == -1, "virEventAddTimeout");
+
+  CAMLreturn(Val_int(r));
+}
+
+CAMLprim value
+ocaml_libvirt_event_remove_timeout (value connv, value timer_id)
+{
+  CAMLparam2 (connv, timer_id);
+  int r;
+
+  NONBLOCKING(r = virEventRemoveTimeout(Int_val(timer_id)));
+  CHECK_ERROR(r == -1, "virEventRemoveTimeout");
+
+  CAMLreturn(Val_int(r));
+}
+
+CAMLprim value
+ocaml_libvirt_connect_domain_event_register_any(value connv, value domv, value callback, value callback_id)
+{
+  CAMLparam4(connv, domv, callback, callback_id);
+
+  virConnectPtr conn = Connect_val (connv);
+  virDomainPtr dom = NULL;
+  int eventID = Tag_val(callback);
+
+  virConnectDomainEventGenericCallback cb;
+  void *opaque;
+  virFreeCallback freecb = free;
+  int r;
+
+  if (domv != Val_int(0))
+    dom = Domain_val (Field(domv, 0));
+
+  switch (eventID){
+  case VIR_DOMAIN_EVENT_ID_LIFECYCLE:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i_i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_REBOOT:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(u_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_RTC_CHANGE:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i64_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_WATCHDOG:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_IO_ERROR:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_GRAPHICS:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i_ga_ga_s_gs_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_i_s_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(u_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(s_i_i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_s_i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_TRAY_CHANGE:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(s_i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_PMWAKEUP:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_PMSUSPEND:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i64_callback);
+    break;
+  case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK:
+    cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
+    break;
+  default:
+    caml_failwith("vifConnectDomainEventRegisterAny: unimplemented eventID");
+  }
+
+  /* Store the int64 callback_id as the opaque data so the OCaml
+     callback can demultiplex to the correct OCaml handler. */
+  if ((opaque = malloc(sizeof(long))) == NULL)
+    caml_failwith ("virConnectDomainEventRegisterAny: malloc");
+  *((long*)opaque) = Int64_val(callback_id);
+  NONBLOCKING(r = virConnectDomainEventRegisterAny(conn, dom, eventID, cb, opaque, freecb));
+  CHECK_ERROR(r == -1, "virConnectDomainEventRegisterAny");
+
+  CAMLreturn(Val_int(r));
+}
+
 CAMLprim value
 ocaml_libvirt_storage_pool_get_info (value poolv)
 {
   CAMLparam1 (poolv);
   CAMLlocal2 (rv, v);
   virStoragePoolPtr pool = Pool_val (poolv);
-  virConnectPtr conn = Connect_polv (poolv);
   virStoragePoolInfo info;
   int r;
 
   NONBLOCKING (r = virStoragePoolGetInfo (pool, &info));
-  CHECK_ERROR (r == -1, conn, "virStoragePoolGetInfo");
+  CHECK_ERROR (r == -1, "virStoragePoolGetInfo");
 
   rv = caml_alloc (4, 0);
   Store_field (rv, 0, Val_int (info.state));
@@ -768,12 +1159,11 @@ ocaml_libvirt_storage_vol_get_info (value volv)
   CAMLparam1 (volv);
   CAMLlocal2 (rv, v);
   virStorageVolPtr vol = Volume_val (volv);
-  virConnectPtr conn = Connect_volv (volv);
   virStorageVolInfo info;
   int r;
 
   NONBLOCKING (r = virStorageVolGetInfo (vol, &info));
-  CHECK_ERROR (r == -1, conn, "virStorageVolGetInfo");
+  CHECK_ERROR (r == -1, "virStorageVolGetInfo");
 
   rv = caml_alloc (3, 0);
   Store_field (rv, 0, Val_int (info.type));
@@ -828,16 +1218,20 @@ ocaml_libvirt_virterror_reset_last_conn_error (value connv)
 
 /*----------------------------------------------------------------------*/
 
+static void
+ignore_errors (void *user_data, virErrorPtr error)
+{
+  /* do nothing */
+}
+
 /* Initialise the library. */
 CAMLprim value
 ocaml_libvirt_init (value unit)
 {
   CAMLparam1 (unit);
-  CAMLlocal1 (rv);
-  int r;
 
-  r = virInitialize ();
-  CHECK_ERROR (r == -1, NULL, "virInitialize");
+  virSetErrorFunc (NULL, ignore_errors);
+  virInitialize ();
 
   CAMLreturn (Val_unit);
 }