libvirt/examples/object-events/event-test.c
Michal Privoznik f7fee15ae8 event-test: Unregister close callback
When registering a close callback, the connection refcount is increased
as the connection object is passed to the callback and hence we must
prevent deleting it too soon. However, when closing the connection, the
connection object is just unrefed. So whenever a connection with a close
callback is closed, we end up with the connection object which has
exactly one reference. Leaving the code as-is doesn't mean the end of
the world as we know it, but why give a bad example?

==14531== 288 bytes in 1 blocks are still reachable in loss record 695 of 762
==14531==    at 0x4C2BDE4: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==14531==    by 0x4E9FE09: virAllocVar (viralloc.c:558)
==14531==    by 0x4EDBE45: virObjectNew (virobject.c:190)
==14531==    by 0x4F71AAC: virGetConnect (datatypes.c:116)
==14531==    by 0x4F78511: do_open (libvirt.c:1136)
==14531==    by 0x4F7B3AC: virConnectOpenAuth (libvirt.c:1481)
==14531==    by 0x4011D2: main (event-test.c:499)

(and other leaks tied to virGetConnect())

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2013-12-24 17:18:34 +01:00

688 lines
26 KiB
C

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <inttypes.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#define VIR_DEBUG(fmt) printf("%s:%d: " fmt "\n", __func__, __LINE__)
#define STREQ(a,b) (strcmp(a,b) == 0)
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__((__unused__))
#endif
int run = 1;
/* Prototypes */
const char *eventToString(int event);
int myEventAddHandleFunc (int fd, int event,
virEventHandleCallback cb,
void *opaque,
virFreeCallback ff);
void myEventUpdateHandleFunc(int watch, int event);
int myEventRemoveHandleFunc(int watch);
int myEventAddTimeoutFunc(int timeout,
virEventTimeoutCallback cb,
void *opaque,
virFreeCallback ff);
void myEventUpdateTimeoutFunc(int timer, int timout);
int myEventRemoveTimeoutFunc(int timer);
int myEventHandleTypeToPollEvent(virEventHandleType events);
virEventHandleType myPollEventToEventHandleType(int events);
void usage(const char *pname);
/* Callback functions */
static void connectClose(virConnectPtr conn ATTRIBUTE_UNUSED,
int reason,
void *opaque ATTRIBUTE_UNUSED)
{
switch (reason) {
case VIR_CONNECT_CLOSE_REASON_ERROR:
fprintf(stderr, "Connection closed due to I/O error\n");
break;
case VIR_CONNECT_CLOSE_REASON_EOF:
fprintf(stderr, "Connection closed due to end of file\n");
break;
case VIR_CONNECT_CLOSE_REASON_KEEPALIVE:
fprintf(stderr, "Connection closed due to keepalive timeout\n");
break;
case VIR_CONNECT_CLOSE_REASON_CLIENT:
fprintf(stderr, "Connection closed due to client request\n");
break;
default:
fprintf(stderr, "Connection closed due to unknown reason\n");
break;
};
run = 0;
}
const char *eventToString(int event) {
const char *ret = "";
switch ((virDomainEventType) event) {
case VIR_DOMAIN_EVENT_DEFINED:
ret ="Defined";
break;
case VIR_DOMAIN_EVENT_UNDEFINED:
ret ="Undefined";
break;
case VIR_DOMAIN_EVENT_STARTED:
ret ="Started";
break;
case VIR_DOMAIN_EVENT_SUSPENDED:
ret ="Suspended";
break;
case VIR_DOMAIN_EVENT_RESUMED:
ret ="Resumed";
break;
case VIR_DOMAIN_EVENT_STOPPED:
ret ="Stopped";
break;
case VIR_DOMAIN_EVENT_SHUTDOWN:
ret = "Shutdown";
break;
case VIR_DOMAIN_EVENT_PMSUSPENDED:
ret = "PMSuspended";
break;
case VIR_DOMAIN_EVENT_CRASHED:
ret = "Crashed";
break;
}
return ret;
}
static const char *eventDetailToString(int event, int detail) {
const char *ret = "";
switch ((virDomainEventType) event) {
case VIR_DOMAIN_EVENT_DEFINED:
if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED)
ret = "Added";
else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED)
ret = "Updated";
break;
case VIR_DOMAIN_EVENT_UNDEFINED:
if (detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED)
ret = "Removed";
break;
case VIR_DOMAIN_EVENT_STARTED:
switch ((virDomainEventStartedDetailType) detail) {
case VIR_DOMAIN_EVENT_STARTED_BOOTED:
ret = "Booted";
break;
case VIR_DOMAIN_EVENT_STARTED_MIGRATED:
ret = "Migrated";
break;
case VIR_DOMAIN_EVENT_STARTED_RESTORED:
ret = "Restored";
break;
case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
case VIR_DOMAIN_EVENT_STARTED_WAKEUP:
ret = "Event wakeup";
break;
}
break;
case VIR_DOMAIN_EVENT_SUSPENDED:
switch ((virDomainEventSuspendedDetailType) detail) {
case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED:
ret = "Paused";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED:
ret = "Migrated";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR:
ret = "I/O Error";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG:
ret = "Watchdog";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED:
ret = "Restored";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR:
ret = "API error";
break;
}
break;
case VIR_DOMAIN_EVENT_RESUMED:
switch ((virDomainEventResumedDetailType) detail) {
case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED:
ret = "Unpaused";
break;
case VIR_DOMAIN_EVENT_RESUMED_MIGRATED:
ret = "Migrated";
break;
case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
}
break;
case VIR_DOMAIN_EVENT_STOPPED:
switch ((virDomainEventStoppedDetailType) detail) {
case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN:
ret = "Shutdown";
break;
case VIR_DOMAIN_EVENT_STOPPED_DESTROYED:
ret = "Destroyed";
break;
case VIR_DOMAIN_EVENT_STOPPED_CRASHED:
ret = "Crashed";
break;
case VIR_DOMAIN_EVENT_STOPPED_MIGRATED:
ret = "Migrated";
break;
case VIR_DOMAIN_EVENT_STOPPED_SAVED:
ret = "Saved";
break;
case VIR_DOMAIN_EVENT_STOPPED_FAILED:
ret = "Failed";
break;
case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT:
ret = "Snapshot";
break;
}
break;
case VIR_DOMAIN_EVENT_SHUTDOWN:
switch ((virDomainEventShutdownDetailType) detail) {
case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED:
ret = "Finished";
break;
}
break;
case VIR_DOMAIN_EVENT_PMSUSPENDED:
switch ((virDomainEventPMSuspendedDetailType) detail) {
case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY:
ret = "Memory";
break;
case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK:
ret = "Disk";
break;
}
break;
case VIR_DOMAIN_EVENT_CRASHED:
switch ((virDomainEventCrashedDetailType) detail) {
case VIR_DOMAIN_EVENT_CRASHED_PANICKED:
ret = "Panicked";
break;
}
break;
}
return ret;
}
static const char *
networkEventToString(int event)
{
const char *ret = "";
switch ((virNetworkEventLifecycleType) event) {
case VIR_NETWORK_EVENT_DEFINED:
ret ="Defined";
break;
case VIR_NETWORK_EVENT_UNDEFINED:
ret ="Undefined";
break;
case VIR_NETWORK_EVENT_STARTED:
ret ="Started";
break;
case VIR_NETWORK_EVENT_STOPPED:
ret ="Stopped";
break;
}
return ret;
}
static int myDomainEventCallback1(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int event,
int detail,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
virDomainGetID(dom), eventToString(event),
eventDetailToString(event, detail));
return 0;
}
static int myDomainEventCallback2(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int event,
int detail,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
virDomainGetID(dom), eventToString(event),
eventDetailToString(event, detail));
return 0;
}
static int myDomainEventRebootCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) rebooted\n", __func__, virDomainGetName(dom),
virDomainGetID(dom));
return 0;
}
static int myDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
long long offset,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) rtc change %" PRIdMAX "\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
(intmax_t)offset);
return 0;
}
static int myDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
unsigned long long actual,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) balloon change %" PRIuMAX "KB\n",
__func__, virDomainGetName(dom), virDomainGetID(dom), (uintmax_t)actual);
return 0;
}
static int myDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int action,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) watchdog action=%d\n", __func__, virDomainGetName(dom),
virDomainGetID(dom), action);
return 0;
}
static int myDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) io error path=%s alias=%s action=%d\n", __func__, virDomainGetName(dom),
virDomainGetID(dom), srcPath, devAlias, action);
return 0;
}
static int myDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque ATTRIBUTE_UNUSED)
{
size_t i;
printf("%s EVENT: Domain %s(%d) graphics ", __func__, virDomainGetName(dom),
virDomainGetID(dom));
switch (phase) {
case VIR_DOMAIN_EVENT_GRAPHICS_CONNECT:
printf("connected ");
break;
case VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE:
printf("initialized ");
break;
case VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT:
printf("disconnected ");
break;
}
printf("local: family=%d node=%s service=%s ",
local->family, local->node, local->service);
printf("remote: family=%d node=%s service=%s ",
remote->family, remote->node, remote->service);
printf("auth: %s ", authScheme);
for (i = 0; i < subject->nidentity; i++) {
printf(" identity: %s=%s",
subject->identities[i].type,
subject->identities[i].name);
}
printf("\n");
return 0;
}
static int myDomainEventControlErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) control error\n", __func__, virDomainGetName(dom),
virDomainGetID(dom));
return 0;
}
const char *diskChangeReasonStrings[] = {
"startupPolicy", /* 0 */
/* add new reason here */
};
static int myDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
oldSrcPath, newSrcPath, devAlias, diskChangeReasonStrings[reason]);
return 0;
}
const char *trayChangeReasonStrings[] = {
"open",
"close",
};
static int myDomainEventTrayChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *devAlias,
int reason,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) removable disk's tray change devAlias: %s reason: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
devAlias, trayChangeReasonStrings[reason]);
return 0;
}
static int myDomainEventPMWakeupCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int reason ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) system pmwakeup\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
return 0;
}
static int myDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int reason ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) system pmsuspend\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
return 0;
}
static int myDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int reason ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) system pmsuspend-disk\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
return 0;
}
static int
myDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *devAlias,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) device removed: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom), devAlias);
return 0;
}
static int myNetworkEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virNetworkPtr dom,
int event,
int detail,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Network %s %s %d\n", __func__, virNetworkGetName(dom),
networkEventToString(event), detail);
return 0;
}
static void myFreeFunc(void *opaque)
{
char *str = opaque;
printf("%s: Freeing [%s]\n", __func__, str);
free(str);
}
/* main test functions */
void usage(const char *pname)
{
printf("%s uri\n", pname);
}
static void stop(int sig)
{
printf("Exiting on signal %d\n", sig);
run = 0;
}
int main(int argc, char **argv)
{
int callback1ret = -1;
int callback2ret = -1;
int callback3ret = -1;
int callback4ret = -1;
int callback5ret = -1;
int callback6ret = -1;
int callback7ret = -1;
int callback8ret = -1;
int callback9ret = -1;
int callback10ret = -1;
int callback11ret = -1;
int callback12ret = -1;
int callback13ret = -1;
int callback14ret = -1;
int callback15ret = -1;
int callback16ret = -1;
struct sigaction action_stop;
memset(&action_stop, 0, sizeof(action_stop));
action_stop.sa_handler = stop;
if (argc > 1 && STREQ(argv[1], "--help")) {
usage(argv[0]);
return -1;
}
if (virInitialize() < 0) {
fprintf(stderr, "Failed to initialize libvirt");
return -1;
}
if (virEventRegisterDefaultImpl() < 0) {
virErrorPtr err = virGetLastError();
fprintf(stderr, "Failed to register event implementation: %s\n",
err && err->message ? err->message: "Unknown error");
return -1;
}
virConnectPtr dconn = NULL;
dconn = virConnectOpenAuth(argc > 1 ? argv[1] : NULL,
virConnectAuthPtrDefault,
VIR_CONNECT_RO);
if (!dconn) {
printf("error opening\n");
return -1;
}
virConnectRegisterCloseCallback(dconn,
connectClose, NULL, NULL);
sigaction(SIGTERM, &action_stop, NULL);
sigaction(SIGINT, &action_stop, NULL);
VIR_DEBUG("Registering event cbs");
/* Add 2 callbacks to prove this works with more than just one */
callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1,
strdup("callback 1"), myFreeFunc);
callback2ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_LIFECYCLE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2),
strdup("callback 2"), myFreeFunc);
callback3ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_REBOOT,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRebootCallback),
strdup("callback reboot"), myFreeFunc);
callback4ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_RTC_CHANGE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRTCChangeCallback),
strdup("callback rtcchange"), myFreeFunc);
callback5ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_WATCHDOG,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventWatchdogCallback),
strdup("callback watchdog"), myFreeFunc);
callback6ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_IO_ERROR,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventIOErrorCallback),
strdup("callback io error"), myFreeFunc);
callback7ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_GRAPHICS,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventGraphicsCallback),
strdup("callback graphics"), myFreeFunc);
callback8ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_CONTROL_ERROR,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventControlErrorCallback),
strdup("callback control error"), myFreeFunc);
callback9ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_DISK_CHANGE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDiskChangeCallback),
strdup("disk change"), myFreeFunc);
callback10ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_TRAY_CHANGE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventTrayChangeCallback),
strdup("tray change"), myFreeFunc);
callback11ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_PMWAKEUP,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMWakeupCallback),
strdup("pmwakeup"), myFreeFunc);
callback12ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_PMSUSPEND,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendCallback),
strdup("pmsuspend"), myFreeFunc);
callback13ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventBalloonChangeCallback),
strdup("callback balloonchange"), myFreeFunc);
callback14ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendDiskCallback),
strdup("pmsuspend-disk"), myFreeFunc);
callback15ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDeviceRemovedCallback),
strdup("device removed"), myFreeFunc);
callback16ret = virConnectNetworkEventRegisterAny(dconn,
NULL,
VIR_NETWORK_EVENT_ID_LIFECYCLE,
VIR_NETWORK_EVENT_CALLBACK(myNetworkEventCallback),
strdup("net callback"), myFreeFunc);
if ((callback1ret != -1) &&
(callback2ret != -1) &&
(callback3ret != -1) &&
(callback4ret != -1) &&
(callback5ret != -1) &&
(callback6ret != -1) &&
(callback7ret != -1) &&
(callback9ret != -1) &&
(callback10ret != -1) &&
(callback11ret != -1) &&
(callback12ret != -1) &&
(callback13ret != -1) &&
(callback14ret != -1) &&
(callback15ret != -1) &&
(callback16ret != -1)) {
if (virConnectSetKeepAlive(dconn, 5, 3) < 0) {
virErrorPtr err = virGetLastError();
fprintf(stderr, "Failed to start keepalive protocol: %s\n",
err && err->message ? err->message : "Unknown error");
run = 0;
}
while (run) {
if (virEventRunDefaultImpl() < 0) {
virErrorPtr err = virGetLastError();
fprintf(stderr, "Failed to run event loop: %s\n",
err && err->message ? err->message : "Unknown error");
}
}
VIR_DEBUG("Deregistering event handlers");
virConnectDomainEventDeregister(dconn, myDomainEventCallback1);
virConnectDomainEventDeregisterAny(dconn, callback2ret);
virConnectDomainEventDeregisterAny(dconn, callback3ret);
virConnectDomainEventDeregisterAny(dconn, callback4ret);
virConnectDomainEventDeregisterAny(dconn, callback5ret);
virConnectDomainEventDeregisterAny(dconn, callback6ret);
virConnectDomainEventDeregisterAny(dconn, callback7ret);
virConnectDomainEventDeregisterAny(dconn, callback9ret);
virConnectDomainEventDeregisterAny(dconn, callback10ret);
virConnectDomainEventDeregisterAny(dconn, callback11ret);
virConnectDomainEventDeregisterAny(dconn, callback12ret);
virConnectDomainEventDeregisterAny(dconn, callback13ret);
virConnectDomainEventDeregisterAny(dconn, callback14ret);
virConnectDomainEventDeregisterAny(dconn, callback15ret);
virConnectNetworkEventDeregisterAny(dconn, callback16ret);
if (callback8ret != -1)
virConnectDomainEventDeregisterAny(dconn, callback8ret);
}
virConnectUnregisterCloseCallback(dconn, connectClose);
VIR_DEBUG("Closing connection");
if (dconn && virConnectClose(dconn) < 0) {
printf("error closing\n");
}
printf("done\n");
return 0;
}