2008-10-23 13:18:18 +00:00
|
|
|
#include <config.h>
|
2008-10-24 13:10:30 +00:00
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
#include <stdio.h>
|
2008-11-19 15:25:24 +00:00
|
|
|
#include <stdlib.h>
|
2008-10-23 13:18:18 +00:00
|
|
|
#include <string.h>
|
2008-11-19 15:25:24 +00:00
|
|
|
#include <signal.h>
|
2008-10-24 13:10:30 +00:00
|
|
|
|
|
|
|
#if HAVE_SYS_POLL_H
|
2010-03-09 18:22:22 +00:00
|
|
|
# include <sys/types.h>
|
|
|
|
# include <sys/poll.h>
|
|
|
|
# include <libvirt/libvirt.h>
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# define DEBUG0(fmt) printf("%s:%d :: " fmt "\n", \
|
2008-12-18 12:25:11 +00:00
|
|
|
__func__, __LINE__)
|
2010-03-09 18:22:22 +00:00
|
|
|
# define DEBUG(fmt, ...) printf("%s:%d: " fmt "\n", \
|
2008-12-18 12:25:11 +00:00
|
|
|
__func__, __LINE__, __VA_ARGS__)
|
2010-03-09 18:22:22 +00:00
|
|
|
# define STREQ(a,b) (strcmp(a,b) == 0)
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifndef ATTRIBUTE_UNUSED
|
|
|
|
# define ATTRIBUTE_UNUSED __attribute__((__unused__))
|
|
|
|
# endif
|
2008-10-23 13:18:18 +00:00
|
|
|
|
|
|
|
/* handle globals */
|
|
|
|
int h_fd = 0;
|
|
|
|
virEventHandleType h_event = 0;
|
|
|
|
virEventHandleCallback h_cb = NULL;
|
2008-11-19 16:24:01 +00:00
|
|
|
virFreeCallback h_ff = NULL;
|
2008-10-23 13:18:18 +00:00
|
|
|
void *h_opaque = NULL;
|
|
|
|
|
|
|
|
/* timeout globals */
|
2010-03-09 18:22:22 +00:00
|
|
|
# define TIMEOUT_MS 1000
|
2008-10-23 13:18:18 +00:00
|
|
|
int t_active = 0;
|
|
|
|
int t_timeout = -1;
|
|
|
|
virEventTimeoutCallback t_cb = NULL;
|
2008-11-19 16:24:01 +00:00
|
|
|
virFreeCallback t_ff = NULL;
|
2008-10-23 13:18:18 +00:00
|
|
|
void *t_opaque = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/* Prototypes */
|
|
|
|
const char *eventToString(int event);
|
|
|
|
int myEventAddHandleFunc (int fd, int event,
|
2008-11-19 16:24:01 +00:00
|
|
|
virEventHandleCallback cb,
|
|
|
|
void *opaque,
|
|
|
|
virFreeCallback ff);
|
2008-11-19 16:19:36 +00:00
|
|
|
void myEventUpdateHandleFunc(int watch, int event);
|
|
|
|
int myEventRemoveHandleFunc(int watch);
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2008-11-19 16:24:01 +00:00
|
|
|
int myEventAddTimeoutFunc(int timeout,
|
|
|
|
virEventTimeoutCallback cb,
|
|
|
|
void *opaque,
|
|
|
|
virFreeCallback ff);
|
2008-10-23 13:18:18 +00:00
|
|
|
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 */
|
|
|
|
|
|
|
|
const char *eventToString(int event) {
|
2008-11-17 16:43:00 +00:00
|
|
|
const char *ret = "";
|
2008-10-23 13:18:18 +00:00
|
|
|
switch(event) {
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_DEFINED:
|
|
|
|
ret ="Defined";
|
2008-10-23 13:18:18 +00:00
|
|
|
break;
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_UNDEFINED:
|
|
|
|
ret ="Undefined";
|
2008-10-23 13:18:18 +00:00
|
|
|
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;
|
2008-11-17 16:43:00 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *eventDetailToString(int event, int detail) {
|
|
|
|
const char *ret = "";
|
|
|
|
switch(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";
|
2008-10-23 13:18:18 +00:00
|
|
|
break;
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED:
|
|
|
|
switch (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;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED:
|
|
|
|
if (detail == VIR_DOMAIN_EVENT_SUSPENDED_PAUSED)
|
2009-05-25 09:44:10 +00:00
|
|
|
ret = "Paused";
|
2008-11-17 16:43:00 +00:00
|
|
|
else if (detail == VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED)
|
|
|
|
ret = "Migrated";
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_EVENT_RESUMED:
|
|
|
|
if (detail == VIR_DOMAIN_EVENT_RESUMED_UNPAUSED)
|
|
|
|
ret = "Unpaused";
|
|
|
|
else if (detail == VIR_DOMAIN_EVENT_RESUMED_MIGRATED)
|
|
|
|
ret = "Migrated";
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_EVENT_STOPPED:
|
|
|
|
switch (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 = "Failed";
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_FAILED:
|
|
|
|
ret = "Failed";
|
|
|
|
break;
|
|
|
|
}
|
2008-10-23 13:18:18 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-03-18 17:47:02 +00:00
|
|
|
static int myDomainEventCallback1(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virDomainPtr dom,
|
|
|
|
int event,
|
|
|
|
int detail,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
2008-10-23 13:18:18 +00:00
|
|
|
{
|
2008-12-18 12:25:11 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
|
2008-11-17 16:43:00 +00:00
|
|
|
virDomainGetID(dom), eventToString(event),
|
|
|
|
eventDetailToString(event, detail));
|
2008-10-23 13:18:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-18 17:47:02 +00:00
|
|
|
static int myDomainEventCallback2(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virDomainPtr dom,
|
|
|
|
int event,
|
|
|
|
int detail,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
2008-10-23 13:18:18 +00:00
|
|
|
{
|
2008-12-18 12:25:11 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
|
2008-11-17 16:43:00 +00:00
|
|
|
virDomainGetID(dom), eventToString(event),
|
|
|
|
eventDetailToString(event, detail));
|
2008-10-23 13:18:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-18 15:25:38 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-03-18 18:28:15 +00:00
|
|
|
static int myDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virDomainPtr dom,
|
|
|
|
long long offset,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) rtc change %lld\n", __func__, virDomainGetName(dom),
|
|
|
|
virDomainGetID(dom), offset);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Add support for an explicit watchdog event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_WATCHDOG
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_WATCHDOG_NONE = 0,
VIR_DOMAIN_EVENT_WATCHDOG_PAUSE,
VIR_DOMAIN_EVENT_WATCHDOG_RESET,
VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF,
VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN,
VIR_DOMAIN_EVENT_WATCHDOG_DEBUG,
} virDomainEventWatchdogAction;
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn,
virDomainPtr dom,
int action,
void *opaque);
* daemon/remote.c: Dispatch watchdog events to client
* examples/domain-events/events-c/event-test.c: Watch for
watchdog events
* include/libvirt/libvirt.h.in: Define new watchdg event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle watchdog events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for watchdogs and emit a libvirt watchdog event
* src/remote/remote_driver.c: Receive and dispatch watchdog
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
watchdog events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for WATCHDOG event
from QEMU monitor
2010-03-18 19:07:48 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Add support for an explicit IO error event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_IO_ERROR
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0,
VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
VIR_DOMAIN_EVENT_IO_ERROR_REPORT,
} virDomainEventIOErrorAction;
In addition it has the source path of the disk that had the
error and its unique device alias. It does not include the
target device name (/dev/sda), since this would preclude
triggering IO errors from other file backed devices (eg
serial ports connected to a file)
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque);
This is currently wired up to the QEMU block IO error events
* daemon/remote.c: Dispatch IO error events to client
* examples/domain-events/events-c/event-test.c: Watch for
IO error events
* include/libvirt/libvirt.h.in: Define new IO error event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle IO error events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block IO errors and emit a libvirt IO error event
* src/remote/remote_driver.c: Receive and dispatch IO error
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
IO error events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event
from QEMU monitor
2010-03-18 19:37:44 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
static int myDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virDomainPtr dom,
|
|
|
|
int phase,
|
|
|
|
virDomainEventGraphicsAddressPtr local,
|
|
|
|
virDomainEventGraphicsAddressPtr remote,
|
|
|
|
const char *authScheme,
|
|
|
|
virDomainEventGraphicsSubjectPtr subject,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
int 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;
|
|
|
|
}
|
|
|
|
|
2008-11-19 15:25:24 +00:00
|
|
|
static void myFreeFunc(void *opaque)
|
|
|
|
{
|
|
|
|
char *str = opaque;
|
2008-12-18 12:25:11 +00:00
|
|
|
printf("%s: Freeing [%s]\n", __func__, str);
|
2008-11-19 15:25:24 +00:00
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
|
|
|
|
/* EventImpl Functions */
|
|
|
|
int myEventHandleTypeToPollEvent(virEventHandleType events)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
if(events & VIR_EVENT_HANDLE_READABLE)
|
|
|
|
ret |= POLLIN;
|
|
|
|
if(events & VIR_EVENT_HANDLE_WRITABLE)
|
|
|
|
ret |= POLLOUT;
|
|
|
|
if(events & VIR_EVENT_HANDLE_ERROR)
|
|
|
|
ret |= POLLERR;
|
|
|
|
if(events & VIR_EVENT_HANDLE_HANGUP)
|
|
|
|
ret |= POLLHUP;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
virEventHandleType myPollEventToEventHandleType(int events)
|
|
|
|
{
|
|
|
|
virEventHandleType ret = 0;
|
|
|
|
if(events & POLLIN)
|
|
|
|
ret |= VIR_EVENT_HANDLE_READABLE;
|
|
|
|
if(events & POLLOUT)
|
|
|
|
ret |= VIR_EVENT_HANDLE_WRITABLE;
|
|
|
|
if(events & POLLERR)
|
|
|
|
ret |= VIR_EVENT_HANDLE_ERROR;
|
|
|
|
if(events & POLLHUP)
|
|
|
|
ret |= VIR_EVENT_HANDLE_HANGUP;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int myEventAddHandleFunc(int fd, int event,
|
2008-11-19 16:24:01 +00:00
|
|
|
virEventHandleCallback cb,
|
|
|
|
void *opaque,
|
|
|
|
virFreeCallback ff)
|
2008-10-23 13:18:18 +00:00
|
|
|
{
|
|
|
|
DEBUG("Add handle %d %d %p %p", fd, event, cb, opaque);
|
|
|
|
h_fd = fd;
|
|
|
|
h_event = myEventHandleTypeToPollEvent(event);
|
|
|
|
h_cb = cb;
|
2008-11-19 16:24:01 +00:00
|
|
|
h_ff = ff;
|
2008-10-23 13:18:18 +00:00
|
|
|
h_opaque = opaque;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void myEventUpdateHandleFunc(int fd, int event)
|
|
|
|
{
|
|
|
|
DEBUG("Updated Handle %d %d", fd, event);
|
|
|
|
h_event = myEventHandleTypeToPollEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int myEventRemoveHandleFunc(int fd)
|
|
|
|
{
|
|
|
|
DEBUG("Removed Handle %d", fd);
|
|
|
|
h_fd = 0;
|
2008-11-19 16:24:01 +00:00
|
|
|
if (h_ff)
|
|
|
|
(h_ff)(h_opaque);
|
2008-10-23 13:18:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-19 16:24:01 +00:00
|
|
|
int myEventAddTimeoutFunc(int timeout,
|
|
|
|
virEventTimeoutCallback cb,
|
|
|
|
void *opaque,
|
|
|
|
virFreeCallback ff)
|
2008-10-23 13:18:18 +00:00
|
|
|
{
|
|
|
|
DEBUG("Adding Timeout %d %p %p", timeout, cb, opaque);
|
|
|
|
t_active = 1;
|
|
|
|
t_timeout = timeout;
|
|
|
|
t_cb = cb;
|
2008-11-19 16:24:01 +00:00
|
|
|
t_ff = ff;
|
2008-10-23 13:18:18 +00:00
|
|
|
t_opaque = opaque;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void myEventUpdateTimeoutFunc(int timer ATTRIBUTE_UNUSED, int timeout)
|
|
|
|
{
|
|
|
|
/*DEBUG("Timeout updated %d %d", timer, timeout);*/
|
|
|
|
t_timeout = timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
int myEventRemoveTimeoutFunc(int timer)
|
|
|
|
{
|
|
|
|
DEBUG("Timeout removed %d", timer);
|
|
|
|
t_active = 0;
|
2008-11-19 16:24:01 +00:00
|
|
|
if (t_ff)
|
|
|
|
(t_ff)(t_opaque);
|
2008-10-23 13:18:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* main test functions */
|
|
|
|
|
|
|
|
void usage(const char *pname)
|
|
|
|
{
|
|
|
|
printf("%s uri\n", pname);
|
|
|
|
}
|
|
|
|
|
2008-11-19 15:25:24 +00:00
|
|
|
int run = 1;
|
|
|
|
|
|
|
|
static void stop(int sig)
|
|
|
|
{
|
|
|
|
printf("Exiting on signal %d\n", sig);
|
|
|
|
run = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int sts;
|
2009-05-25 09:44:10 +00:00
|
|
|
int callback1ret = -1;
|
|
|
|
int callback2ret = -1;
|
2010-03-18 15:25:38 +00:00
|
|
|
int callback3ret = -1;
|
2010-03-18 18:28:15 +00:00
|
|
|
int callback4ret = -1;
|
Add support for an explicit watchdog event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_WATCHDOG
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_WATCHDOG_NONE = 0,
VIR_DOMAIN_EVENT_WATCHDOG_PAUSE,
VIR_DOMAIN_EVENT_WATCHDOG_RESET,
VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF,
VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN,
VIR_DOMAIN_EVENT_WATCHDOG_DEBUG,
} virDomainEventWatchdogAction;
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn,
virDomainPtr dom,
int action,
void *opaque);
* daemon/remote.c: Dispatch watchdog events to client
* examples/domain-events/events-c/event-test.c: Watch for
watchdog events
* include/libvirt/libvirt.h.in: Define new watchdg event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle watchdog events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for watchdogs and emit a libvirt watchdog event
* src/remote/remote_driver.c: Receive and dispatch watchdog
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
watchdog events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for WATCHDOG event
from QEMU monitor
2010-03-18 19:07:48 +00:00
|
|
|
int callback5ret = -1;
|
Add support for an explicit IO error event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_IO_ERROR
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0,
VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
VIR_DOMAIN_EVENT_IO_ERROR_REPORT,
} virDomainEventIOErrorAction;
In addition it has the source path of the disk that had the
error and its unique device alias. It does not include the
target device name (/dev/sda), since this would preclude
triggering IO errors from other file backed devices (eg
serial ports connected to a file)
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque);
This is currently wired up to the QEMU block IO error events
* daemon/remote.c: Dispatch IO error events to client
* examples/domain-events/events-c/event-test.c: Watch for
IO error events
* include/libvirt/libvirt.h.in: Define new IO error event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle IO error events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block IO errors and emit a libvirt IO error event
* src/remote/remote_driver.c: Receive and dispatch IO error
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
IO error events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event
from QEMU monitor
2010-03-18 19:37:44 +00:00
|
|
|
int callback6ret = -1;
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
int callback7ret = -1;
|
2010-03-18 17:47:02 +00:00
|
|
|
|
2008-11-19 15:25:24 +00:00
|
|
|
struct sigaction action_stop = {
|
|
|
|
.sa_handler = stop
|
|
|
|
};
|
2008-10-23 13:18:18 +00:00
|
|
|
|
|
|
|
if(argc > 1 && STREQ(argv[1],"--help")) {
|
|
|
|
usage(argv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-11-19 15:25:24 +00:00
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
virEventRegisterImpl( myEventAddHandleFunc,
|
|
|
|
myEventUpdateHandleFunc,
|
|
|
|
myEventRemoveHandleFunc,
|
|
|
|
myEventAddTimeoutFunc,
|
|
|
|
myEventUpdateTimeoutFunc,
|
|
|
|
myEventRemoveTimeoutFunc);
|
|
|
|
|
|
|
|
virConnectPtr dconn = NULL;
|
2010-03-18 17:47:02 +00:00
|
|
|
dconn = virConnectOpenReadOnly (argv[1] ? argv[1] : NULL);
|
2008-10-23 13:18:18 +00:00
|
|
|
if (!dconn) {
|
|
|
|
printf("error opening\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-11-19 15:25:24 +00:00
|
|
|
sigaction(SIGTERM, &action_stop, NULL);
|
|
|
|
sigaction(SIGINT, &action_stop, NULL);
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
DEBUG0("Registering domain event cbs");
|
|
|
|
|
|
|
|
/* Add 2 callbacks to prove this works with more than just one */
|
2009-05-25 09:44:10 +00:00
|
|
|
callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1,
|
|
|
|
strdup("callback 1"), myFreeFunc);
|
2010-03-18 17:47:02 +00:00
|
|
|
callback2ret = virConnectDomainEventRegisterAny(dconn,
|
|
|
|
NULL,
|
|
|
|
VIR_DOMAIN_EVENT_ID_LIFECYCLE,
|
|
|
|
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2),
|
|
|
|
strdup("callback 2"), myFreeFunc);
|
2010-03-18 15:25:38 +00:00
|
|
|
callback3ret = virConnectDomainEventRegisterAny(dconn,
|
|
|
|
NULL,
|
|
|
|
VIR_DOMAIN_EVENT_ID_REBOOT,
|
|
|
|
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRebootCallback),
|
|
|
|
strdup("callback reboot"), myFreeFunc);
|
2010-03-18 18:28:15 +00:00
|
|
|
callback4ret = virConnectDomainEventRegisterAny(dconn,
|
|
|
|
NULL,
|
|
|
|
VIR_DOMAIN_EVENT_ID_RTC_CHANGE,
|
|
|
|
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRTCChangeCallback),
|
|
|
|
strdup("callback rtcchange"), myFreeFunc);
|
Add support for an explicit watchdog event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_WATCHDOG
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_WATCHDOG_NONE = 0,
VIR_DOMAIN_EVENT_WATCHDOG_PAUSE,
VIR_DOMAIN_EVENT_WATCHDOG_RESET,
VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF,
VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN,
VIR_DOMAIN_EVENT_WATCHDOG_DEBUG,
} virDomainEventWatchdogAction;
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn,
virDomainPtr dom,
int action,
void *opaque);
* daemon/remote.c: Dispatch watchdog events to client
* examples/domain-events/events-c/event-test.c: Watch for
watchdog events
* include/libvirt/libvirt.h.in: Define new watchdg event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle watchdog events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for watchdogs and emit a libvirt watchdog event
* src/remote/remote_driver.c: Receive and dispatch watchdog
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
watchdog events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for WATCHDOG event
from QEMU monitor
2010-03-18 19:07:48 +00:00
|
|
|
callback5ret = virConnectDomainEventRegisterAny(dconn,
|
|
|
|
NULL,
|
|
|
|
VIR_DOMAIN_EVENT_ID_WATCHDOG,
|
|
|
|
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventWatchdogCallback),
|
|
|
|
strdup("callback watchdog"), myFreeFunc);
|
Add support for an explicit IO error event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_IO_ERROR
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0,
VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
VIR_DOMAIN_EVENT_IO_ERROR_REPORT,
} virDomainEventIOErrorAction;
In addition it has the source path of the disk that had the
error and its unique device alias. It does not include the
target device name (/dev/sda), since this would preclude
triggering IO errors from other file backed devices (eg
serial ports connected to a file)
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque);
This is currently wired up to the QEMU block IO error events
* daemon/remote.c: Dispatch IO error events to client
* examples/domain-events/events-c/event-test.c: Watch for
IO error events
* include/libvirt/libvirt.h.in: Define new IO error event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle IO error events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block IO errors and emit a libvirt IO error event
* src/remote/remote_driver.c: Receive and dispatch IO error
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
IO error events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event
from QEMU monitor
2010-03-18 19:37:44 +00:00
|
|
|
callback6ret = virConnectDomainEventRegisterAny(dconn,
|
|
|
|
NULL,
|
|
|
|
VIR_DOMAIN_EVENT_ID_IO_ERROR,
|
|
|
|
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventIOErrorCallback),
|
|
|
|
strdup("callback io error"), myFreeFunc);
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
callback7ret = virConnectDomainEventRegisterAny(dconn,
|
|
|
|
NULL,
|
|
|
|
VIR_DOMAIN_EVENT_ID_GRAPHICS,
|
|
|
|
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventGraphicsCallback),
|
|
|
|
strdup("callback graphics"), myFreeFunc);
|
2010-03-18 17:47:02 +00:00
|
|
|
|
|
|
|
if ((callback1ret != -1) &&
|
2010-03-18 15:25:38 +00:00
|
|
|
(callback2ret != -1) &&
|
2010-03-18 18:28:15 +00:00
|
|
|
(callback3ret != -1) &&
|
Add support for an explicit watchdog event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_WATCHDOG
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_WATCHDOG_NONE = 0,
VIR_DOMAIN_EVENT_WATCHDOG_PAUSE,
VIR_DOMAIN_EVENT_WATCHDOG_RESET,
VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF,
VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN,
VIR_DOMAIN_EVENT_WATCHDOG_DEBUG,
} virDomainEventWatchdogAction;
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn,
virDomainPtr dom,
int action,
void *opaque);
* daemon/remote.c: Dispatch watchdog events to client
* examples/domain-events/events-c/event-test.c: Watch for
watchdog events
* include/libvirt/libvirt.h.in: Define new watchdg event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle watchdog events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for watchdogs and emit a libvirt watchdog event
* src/remote/remote_driver.c: Receive and dispatch watchdog
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
watchdog events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for WATCHDOG event
from QEMU monitor
2010-03-18 19:07:48 +00:00
|
|
|
(callback4ret != -1) &&
|
Add support for an explicit IO error event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_IO_ERROR
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0,
VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
VIR_DOMAIN_EVENT_IO_ERROR_REPORT,
} virDomainEventIOErrorAction;
In addition it has the source path of the disk that had the
error and its unique device alias. It does not include the
target device name (/dev/sda), since this would preclude
triggering IO errors from other file backed devices (eg
serial ports connected to a file)
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque);
This is currently wired up to the QEMU block IO error events
* daemon/remote.c: Dispatch IO error events to client
* examples/domain-events/events-c/event-test.c: Watch for
IO error events
* include/libvirt/libvirt.h.in: Define new IO error event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle IO error events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block IO errors and emit a libvirt IO error event
* src/remote/remote_driver.c: Receive and dispatch IO error
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
IO error events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event
from QEMU monitor
2010-03-18 19:37:44 +00:00
|
|
|
(callback5ret != -1) &&
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
(callback6ret != -1) &&
|
|
|
|
(callback7ret != -1)) {
|
2009-05-25 09:44:10 +00:00
|
|
|
while(run) {
|
|
|
|
struct pollfd pfd = { .fd = h_fd,
|
|
|
|
.events = h_event,
|
|
|
|
.revents = 0};
|
|
|
|
|
|
|
|
sts = poll(&pfd, 1, TIMEOUT_MS);
|
|
|
|
|
2010-01-26 01:54:34 +00:00
|
|
|
/* if t_timeout < 0 then t_cb must not be called */
|
|
|
|
if (t_cb && t_active && t_timeout >= 0) {
|
2009-05-25 09:44:10 +00:00
|
|
|
t_cb(t_timeout,t_opaque);
|
2010-01-26 01:54:34 +00:00
|
|
|
}
|
2009-05-25 09:44:10 +00:00
|
|
|
|
|
|
|
if (sts == 0) {
|
|
|
|
/* DEBUG0("Poll timeout"); */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (sts < 0 ) {
|
|
|
|
DEBUG0("Poll failed");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( pfd.revents & POLLHUP ) {
|
|
|
|
DEBUG0("Reset by peer");
|
|
|
|
return -1;
|
|
|
|
}
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2009-05-25 09:44:10 +00:00
|
|
|
if(h_cb) {
|
|
|
|
h_cb(0,
|
|
|
|
h_fd,
|
|
|
|
myPollEventToEventHandleType(pfd.revents & h_event),
|
|
|
|
h_opaque);
|
|
|
|
}
|
2008-10-23 13:18:18 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-05-25 09:44:10 +00:00
|
|
|
DEBUG0("Deregistering event handlers");
|
|
|
|
virConnectDomainEventDeregister(dconn, myDomainEventCallback1);
|
2010-03-18 17:47:02 +00:00
|
|
|
virConnectDomainEventDeregisterAny(dconn, callback2ret);
|
2010-03-18 15:25:38 +00:00
|
|
|
virConnectDomainEventDeregisterAny(dconn, callback3ret);
|
2010-03-18 18:28:15 +00:00
|
|
|
virConnectDomainEventDeregisterAny(dconn, callback4ret);
|
Add support for an explicit watchdog event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_WATCHDOG
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_WATCHDOG_NONE = 0,
VIR_DOMAIN_EVENT_WATCHDOG_PAUSE,
VIR_DOMAIN_EVENT_WATCHDOG_RESET,
VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF,
VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN,
VIR_DOMAIN_EVENT_WATCHDOG_DEBUG,
} virDomainEventWatchdogAction;
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn,
virDomainPtr dom,
int action,
void *opaque);
* daemon/remote.c: Dispatch watchdog events to client
* examples/domain-events/events-c/event-test.c: Watch for
watchdog events
* include/libvirt/libvirt.h.in: Define new watchdg event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle watchdog events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for watchdogs and emit a libvirt watchdog event
* src/remote/remote_driver.c: Receive and dispatch watchdog
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
watchdog events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for WATCHDOG event
from QEMU monitor
2010-03-18 19:07:48 +00:00
|
|
|
virConnectDomainEventDeregisterAny(dconn, callback5ret);
|
Add support for an explicit IO error event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_IO_ERROR
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0,
VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
VIR_DOMAIN_EVENT_IO_ERROR_REPORT,
} virDomainEventIOErrorAction;
In addition it has the source path of the disk that had the
error and its unique device alias. It does not include the
target device name (/dev/sda), since this would preclude
triggering IO errors from other file backed devices (eg
serial ports connected to a file)
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque);
This is currently wired up to the QEMU block IO error events
* daemon/remote.c: Dispatch IO error events to client
* examples/domain-events/events-c/event-test.c: Watch for
IO error events
* include/libvirt/libvirt.h.in: Define new IO error event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle IO error events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block IO errors and emit a libvirt IO error event
* src/remote/remote_driver.c: Receive and dispatch IO error
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
IO error events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event
from QEMU monitor
2010-03-18 19:37:44 +00:00
|
|
|
virConnectDomainEventDeregisterAny(dconn, callback6ret);
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
virConnectDomainEventDeregisterAny(dconn, callback7ret);
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|
|
|
|
|
2008-11-19 15:25:24 +00:00
|
|
|
DEBUG0("Closing connection");
|
2008-10-23 13:18:18 +00:00
|
|
|
if( dconn && virConnectClose(dconn)<0 ) {
|
|
|
|
printf("error closing\n");
|
|
|
|
}
|
2008-11-19 15:25:24 +00:00
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
printf("done\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-24 13:10:30 +00:00
|
|
|
#else
|
|
|
|
int main(void) {
|
|
|
|
printf("event-test program not available without sys/poll.h support\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|