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
This commit is contained in:
Daniel P. Berrange 2010-03-19 13:27:45 +00:00
parent 71d793faaf
commit 987e31edc9
16 changed files with 740 additions and 3 deletions

View File

@ -251,12 +251,77 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
}
static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque)
{
struct qemud_client *client = opaque;
remote_domain_event_graphics_msg data;
int i;
if (!client)
return -1;
REMOTE_DEBUG("Relaying domain graphics event %s %d %d - %d %s %s - %d %s %s - %s", dom->name, dom->id, phase,
local->family, local->service, local->node,
remote->family, remote->service, remote->node,
authScheme);
REMOTE_DEBUG("Subject %d", subject->nidentity);
for (i = 0 ; i < subject->nidentity ; i++) {
REMOTE_DEBUG(" %s=%s", subject->identities[i].type, subject->identities[i].name);
}
virMutexLock(&client->lock);
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain (&data.dom, dom);
data.phase = phase;
data.authScheme = (char*)authScheme;
data.local.family = local->family;
data.local.node = (char *)local->node;
data.local.service = (char *)local->service;
data.remote.family = remote->family;
data.remote.node = (char*)remote->node;
data.remote.service = (char*)remote->service;
data.subject.subject_len = subject->nidentity;
if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0) {
VIR_WARN0("cannot allocate memory for graphics event subject");
return -1;
}
for (i = 0 ; i < data.subject.subject_len ; i++) {
data.subject.subject_val[i].type = (char*)subject->identities[i].type;
data.subject.subject_val[i].name = (char*)subject->identities[i].name;
}
remoteDispatchDomainEventSend (client,
REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
(xdrproc_t)xdr_remote_domain_event_graphics_msg, &data);
VIR_FREE(data.subject.subject_val);
virMutexUnlock(&client->lock);
return 0;
}
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventRTCChange),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventWatchdog),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOError),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);

View File

@ -867,3 +867,8 @@
.args_filter = (xdrproc_t) xdr_void,
.ret_filter = (xdrproc_t) xdr_void,
},
{ /* Async event DomainEventGraphics => 171 */
.fn = NULL,
.args_filter = (xdrproc_t) xdr_void,
.ret_filter = (xdrproc_t) xdr_void,
},

View File

@ -217,6 +217,47 @@ static int myDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
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)
{
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;
}
static void myFreeFunc(void *opaque)
{
char *str = opaque;
@ -338,6 +379,7 @@ int main(int argc, char **argv)
int callback4ret = -1;
int callback5ret = -1;
int callback6ret = -1;
int callback7ret = -1;
struct sigaction action_stop = {
.sa_handler = stop
@ -395,13 +437,19 @@ int main(int argc, char **argv)
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);
if ((callback1ret != -1) &&
(callback2ret != -1) &&
(callback3ret != -1) &&
(callback4ret != -1) &&
(callback5ret != -1) &&
(callback6ret != -1)) {
(callback6ret != -1) &&
(callback7ret != -1)) {
while(run) {
struct pollfd pfd = { .fd = h_fd,
.events = h_event,
@ -443,6 +491,7 @@ int main(int argc, char **argv)
virConnectDomainEventDeregisterAny(dconn, callback4ret);
virConnectDomainEventDeregisterAny(dconn, callback5ret);
virConnectDomainEventDeregisterAny(dconn, callback6ret);
virConnectDomainEventDeregisterAny(dconn, callback7ret);
}
DEBUG0("Closing connection");

View File

@ -1940,6 +1940,98 @@ typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
int action,
void *opaque);
/**
* virDomainEventGraphicsPhase:
*
* The phase of the graphics client connection
*/
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0, /* Initial socket connection established */
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE, /* Authentication & setup completed */
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT, /* Final socket disconnection */
} virDomainEventGraphicsPhase;
/**
* virDomainEventGraphicsAddressType:
*
* The type of address for the connection
*/
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4, /* IPv4 address */
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6, /* IPv6 address */
} virDomainEventGraphicsAddressType;
/**
* virDomainEventGraphicsAddress:
*
* The data structure containing connection address details
*
*/
struct _virDomainEventGraphicsAddress {
int family; /* Address family, virDomainEventGraphicsAddressType */
const char *node; /* Address of node (eg IP address) */
const char *service; /* Service name/number (eg TCP port) */
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
/**
* virDomainEventGraphicsSubjectIdentity:
*
* The data structure representing a single identity
*
* The types of identity differ according to the authentication scheme,
* some examples are 'x509dname' and 'saslUsername'.
*/
struct _virDomainEventGraphicsSubjectIdentity {
const char *type; /* Type of identity */
const char *name; /* Identity value */
};
typedef struct _virDomainEventGraphicsSubjectIdentity virDomainEventGraphicsSubjectIdentity;
typedef virDomainEventGraphicsSubjectIdentity *virDomainEventGraphicsSubjectIdentityPtr;
/**
* virDomainEventGraphicsSubject:
*
* The data structure representing an authenticated subject
*
* A subject will have zero or more identities. The types of
* identity differ according to the authentication scheme
*/
struct _virDomainEventGraphicsSubject {
int nidentity; /* Number of identities in array*/
virDomainEventGraphicsSubjectIdentityPtr identities; /* Array of identities for subject */
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
/**
* virConnectDomainEventGraphicsCallback:
* @conn: connection object
* @dom: domain on which the event occurred
* @phase: the phase of the connection
* @local: the local server address
* @remote: the remote client address
* @authScheme: the authentication scheme activated
* @subject: the authenticated subject (user)
* @opaque: application specified data
*
* The callback signature to use when registering for an event of type
* VIR_DOMAIN_EVENT_ID_GRAPHICS with virConnectDomainEventRegisterAny()
*/
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
@ -1955,6 +2047,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_RTC_CHANGE = 2, /* virConnectDomainEventRTCChangeCallback */
VIR_DOMAIN_EVENT_ID_WATCHDOG = 3, /* virConnectDomainEventWatchdogCallback */
VIR_DOMAIN_EVENT_ID_IO_ERROR = 4, /* virConnectDomainEventIOErrorCallback */
VIR_DOMAIN_EVENT_ID_GRAPHICS = 5, /* virConnectDomainEventGraphicsCallback */
/*
* NB: this enum value will increase over time as new events are

View File

@ -173,6 +173,7 @@ skipped_types = {
'virConnectDomainEventRTCChangeCallback': "No function types in python",
'virConnectDomainEventWatchdogCallback': "No function types in python",
'virConnectDomainEventIOErrorCallback': "No function types in python",
'virConnectDomainEventGraphicsCallback': "No function types in python",
'virEventAddHandleFunc': "No function types in python",
}

View File

@ -75,6 +75,13 @@ struct _virDomainEvent {
char *devAlias;
int action;
} ioError;
struct {
int phase;
virDomainEventGraphicsAddressPtr local;
virDomainEventGraphicsAddressPtr remote;
char *authScheme;
virDomainEventGraphicsSubjectPtr subject;
} graphics;
} data;
};
@ -463,9 +470,32 @@ void virDomainEventFree(virDomainEventPtr event)
if (!event)
return;
if (event->eventID == VIR_DOMAIN_EVENT_ID_IO_ERROR) {
switch (event->eventID) {
case VIR_DOMAIN_EVENT_ID_IO_ERROR:
VIR_FREE(event->data.ioError.srcPath);
VIR_FREE(event->data.ioError.devAlias);
break;
case VIR_DOMAIN_EVENT_ID_GRAPHICS:
if (event->data.graphics.local) {
VIR_FREE(event->data.graphics.local->node);
VIR_FREE(event->data.graphics.local->service);
VIR_FREE(event->data.graphics.local);
}
if (event->data.graphics.remote) {
VIR_FREE(event->data.graphics.remote->node);
VIR_FREE(event->data.graphics.remote->service);
VIR_FREE(event->data.graphics.remote);
}
VIR_FREE(event->data.graphics.authScheme);
if (event->data.graphics.subject) {
int i;
for (i = 0 ; i < event->data.graphics.subject->nidentity ; i++) {
VIR_FREE(event->data.graphics.subject->identities[i].type);
VIR_FREE(event->data.graphics.subject->identities[i].name);
}
VIR_FREE(event->data.graphics.subject);
}
}
VIR_FREE(event->dom.name);
@ -641,6 +671,58 @@ virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj,
return ev;
}
virDomainEventPtr virDomainEventGraphicsNewFromDom(virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject)
{
virDomainEventPtr ev =
virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_GRAPHICS,
dom->id, dom->name, dom->uuid);
if (ev) {
ev->data.graphics.phase = phase;
if (!(ev->data.graphics.authScheme = strdup(authScheme))) {
virDomainEventFree(ev);
ev = NULL;
}
ev->data.graphics.local = local;
ev->data.graphics.remote = remote;
ev->data.graphics.subject = subject;
}
return ev;
}
virDomainEventPtr virDomainEventGraphicsNewFromObj(virDomainObjPtr obj,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject)
{
virDomainEventPtr ev =
virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_GRAPHICS,
obj->def->id, obj->def->name, obj->def->uuid);
if (ev) {
ev->data.graphics.phase = phase;
if (!(ev->data.graphics.authScheme = strdup(authScheme))) {
virDomainEventFree(ev);
ev = NULL;
}
ev->data.graphics.local = local;
ev->data.graphics.remote = remote;
ev->data.graphics.subject = subject;
}
return ev;
}
/**
* virDomainEventQueueFree:
* @queue: pointer to the queue
@ -771,6 +853,16 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
case VIR_DOMAIN_EVENT_ID_GRAPHICS:
((virConnectDomainEventGraphicsCallback)cb)(conn, dom,
event->data.graphics.phase,
event->data.graphics.local,
event->data.graphics.remote,
event->data.graphics.authScheme,
event->data.graphics.subject,
cbopaque);
break;
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;

View File

@ -130,6 +130,21 @@ virDomainEventPtr virDomainEventIOErrorNewFromObj(virDomainObjPtr obj,
const char *devAlias,
int action);
virDomainEventPtr virDomainEventGraphicsNewFromDom(virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject);
virDomainEventPtr virDomainEventGraphicsNewFromObj(virDomainObjPtr obj,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject);
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);

View File

@ -222,6 +222,8 @@ virDomainEventWatchdogNewFromDom;
virDomainEventWatchdogNewFromObj;
virDomainEventIOErrorNewFromDom;
virDomainEventIOErrorNewFromObj;
virDomainEventGraphicsNewFromDom;
virDomainEventGraphicsNewFromObj;
virDomainEventFree;
virDomainEventDispatchDefaultFunc;
virDomainEventDispatch;

View File

@ -993,6 +993,98 @@ qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
}
static int
qemuHandleDomainGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
int phase,
int localFamily,
const char *localNode,
const char *localService,
int remoteFamily,
const char *remoteNode,
const char *remoteService,
const char *authScheme,
const char *x509dname,
const char *saslUsername)
{
struct qemud_driver *driver = qemu_driver;
virDomainEventPtr event;
virDomainEventGraphicsAddressPtr localAddr = NULL;
virDomainEventGraphicsAddressPtr remoteAddr = NULL;
virDomainEventGraphicsSubjectPtr subject = NULL;
int i;
virDomainObjLock(vm);
if (VIR_ALLOC(localAddr) < 0)
goto no_memory;
localAddr->family = localFamily;
if (!(localAddr->service = strdup(localService)) ||
!(localAddr->node = strdup(localNode)))
goto no_memory;
if (VIR_ALLOC(remoteAddr) < 0)
goto no_memory;
remoteAddr->family = remoteFamily;
if (!(remoteAddr->service = strdup(remoteService)) ||
!(remoteAddr->node = strdup(remoteNode)))
goto no_memory;
if (VIR_ALLOC(subject) < 0)
goto no_memory;
if (x509dname) {
if (VIR_REALLOC_N(subject->identities, subject->nidentity+1) < 0)
goto no_memory;
if (!(subject->identities[subject->nidentity].type = strdup("x509dname")) ||
!(subject->identities[subject->nidentity].name = strdup(x509dname)))
goto no_memory;
subject->nidentity++;
}
if (saslUsername) {
if (VIR_REALLOC_N(subject->identities, subject->nidentity+1) < 0)
goto no_memory;
if (!(subject->identities[subject->nidentity].type = strdup("saslUsername")) ||
!(subject->identities[subject->nidentity].name = strdup(saslUsername)))
goto no_memory;
subject->nidentity++;
}
event = virDomainEventGraphicsNewFromObj(vm, phase, localAddr, remoteAddr, authScheme, subject);
virDomainObjUnlock(vm);
if (event) {
qemuDriverLock(driver);
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
}
return 0;
no_memory:
virReportOOMError();
if (localAddr) {
VIR_FREE(localAddr->service);
VIR_FREE(localAddr->node);
VIR_FREE(localAddr);
}
if (remoteAddr) {
VIR_FREE(remoteAddr->service);
VIR_FREE(remoteAddr->node);
VIR_FREE(remoteAddr);
}
if (subject) {
for (i = 0 ; i < subject->nidentity ; i++) {
VIR_FREE(subject->identities[i].type);
VIR_FREE(subject->identities[i].name);
}
VIR_FREE(subject->identities);
VIR_FREE(subject);
}
return -1;
}
static qemuMonitorCallbacks monitorCallbacks = {
.eofNotify = qemuHandleMonitorEOF,
.diskSecretLookup = findVolumeQcowPassphrase,
@ -1000,6 +1092,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainRTCChange = qemuHandleDomainRTCChange,
.domainWatchdog = qemuHandleDomainWatchdog,
.domainIOError = qemuHandleDomainIOError,
.domainGraphics = qemuHandleDomainGraphics,
};
static int

View File

@ -838,6 +838,36 @@ int qemuMonitorEmitIOError(qemuMonitorPtr mon,
}
int qemuMonitorEmitGraphics(qemuMonitorPtr mon,
int phase,
int localFamily,
const char *localNode,
const char *localService,
int remoteFamily,
const char *remoteNode,
const char *remoteService,
const char *authScheme,
const char *x509dname,
const char *saslUsername)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
qemuMonitorRef(mon);
qemuMonitorUnlock(mon);
if (mon->cb && mon->cb->domainGraphics)
ret = mon->cb->domainGraphics(mon, mon->vm,
phase,
localFamily, localNode, localService,
remoteFamily, remoteNode, remoteService,
authScheme, x509dname, saslUsername);
qemuMonitorLock(mon);
qemuMonitorUnref(mon);
return ret;
}
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
{
int ret;

View File

@ -96,6 +96,18 @@ struct _qemuMonitorCallbacks {
virDomainObjPtr vm,
const char *diskAlias,
int action);
int (*domainGraphics)(qemuMonitorPtr mon,
virDomainObjPtr vm,
int phase,
int localFamily,
const char *localNode,
const char *localService,
int remoteFamily,
const char *remoteNode,
const char *remoteService,
const char *authScheme,
const char *x509dname,
const char *saslUsername);
};
@ -137,6 +149,18 @@ int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action);
int qemuMonitorEmitIOError(qemuMonitorPtr mon,
const char *diskAlias,
int action);
int qemuMonitorEmitGraphics(qemuMonitorPtr mon,
int phase,
int localFamily,
const char *localNode,
const char *localService,
int remoteFamily,
const char *remoteNode,
const char *remoteService,
const char *authScheme,
const char *x509dname,
const char *saslUsername);
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
virConnectPtr conn);

View File

@ -52,6 +52,9 @@ static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
struct {
const char *type;
@ -64,6 +67,9 @@ struct {
{ "RTC_CHANGE", qemuMonitorJSONHandleRTCChange, },
{ "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
{ "DISK_IO_ERROR", qemuMonitorJSONHandleIOError, },
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
};
@ -566,6 +572,74 @@ static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr dat
}
VIR_ENUM_DECL(qemuMonitorGraphicsAddressFamily)
VIR_ENUM_IMPL(qemuMonitorGraphicsAddressFamily, VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6 + 1,
"ipv4", "ipv6");
static void qemuMonitorJSONHandleVNC(qemuMonitorPtr mon, virJSONValuePtr data, int phase)
{
const char *localNode, *localService, *localFamily;
const char *remoteNode, *remoteService, *remoteFamily;
const char *authScheme, *saslUsername, *x509dname;
int localFamilyID, remoteFamilyID;
virJSONValuePtr client;
virJSONValuePtr server;
if (!(client = virJSONValueObjectGet(data, "client"))) {
VIR_WARN0("missing client info in VNC event");
return;
}
if (!(server = virJSONValueObjectGet(data, "server"))) {
VIR_WARN0("missing server info in VNC event");
return;
}
authScheme = virJSONValueObjectGetString(server, "auth");
localFamily = virJSONValueObjectGetString(server, "family");
localNode = virJSONValueObjectGetString(server, "host");
localService = virJSONValueObjectGetString(server, "service");
remoteFamily = virJSONValueObjectGetString(client, "family");
remoteNode = virJSONValueObjectGetString(client, "host");
remoteService = virJSONValueObjectGetString(client, "service");
saslUsername = virJSONValueObjectGetString(client, "sasl_username");
x509dname = virJSONValueObjectGetString(client, "x509_dname");
if ((localFamilyID = qemuMonitorGraphicsAddressFamilyTypeFromString(localFamily)) < 0) {
VIR_WARN("unknown address family '%s'", localFamily);
localFamilyID = VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4;
}
if ((remoteFamilyID = qemuMonitorGraphicsAddressFamilyTypeFromString(remoteFamily)) < 0) {
VIR_WARN("unknown address family '%s'", remoteFamily);
remoteFamilyID = VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4;
}
qemuMonitorEmitGraphics(mon, phase,
localFamilyID, localNode, localService,
remoteFamilyID, remoteNode, remoteService,
authScheme, x509dname, saslUsername);
}
static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data)
{
qemuMonitorJSONHandleVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT);
}
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data)
{
qemuMonitorJSONHandleVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE);
}
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data)
{
qemuMonitorJSONHandleVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
}
int
qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon)
{

View File

@ -7024,6 +7024,94 @@ remoteDomainReadEventIOError(virConnectPtr conn, XDR *xdr)
}
static virDomainEventPtr
remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
{
remote_domain_event_graphics_msg msg;
virDomainPtr dom;
virDomainEventPtr event = NULL;
virDomainEventGraphicsAddressPtr localAddr = NULL;
virDomainEventGraphicsAddressPtr remoteAddr = NULL;
virDomainEventGraphicsSubjectPtr subject = NULL;
int i;
memset (&msg, 0, sizeof msg);
/* unmarshall parameters, and process it*/
if (! xdr_remote_domain_event_graphics_msg(xdr, &msg) ) {
error (conn, VIR_ERR_RPC,
_("unable to demarshall reboot event"));
return NULL;
}
dom = get_nonnull_domain(conn,msg.dom);
if (!dom)
return NULL;
if (VIR_ALLOC(localAddr) < 0)
goto no_memory;
localAddr->family = msg.local.family;
if (!(localAddr->service = strdup(msg.local.service)) ||
!(localAddr->node = strdup(msg.local.node)))
goto no_memory;
if (VIR_ALLOC(remoteAddr) < 0)
goto no_memory;
remoteAddr->family = msg.remote.family;
if (!(remoteAddr->service = strdup(msg.remote.service)) ||
!(remoteAddr->node = strdup(msg.remote.node)))
goto no_memory;
fprintf(stderr, "Got %d\n", msg.subject.subject_len);
if (VIR_ALLOC(subject) < 0)
goto no_memory;
if (VIR_ALLOC_N(subject->identities, msg.subject.subject_len) < 0)
goto no_memory;
subject->nidentity = msg.subject.subject_len;
for (i = 0 ; i < subject->nidentity ; i++) {
fprintf(stderr, " %s=%s\n", msg.subject.subject_val[i].type,
msg.subject.subject_val[i].name);
if (!(subject->identities[i].type = strdup(msg.subject.subject_val[i].type)) ||
!(subject->identities[i].name = strdup(msg.subject.subject_val[i].name)))
goto no_memory;
}
event = virDomainEventGraphicsNewFromDom(dom,
msg.phase,
localAddr,
remoteAddr,
msg.authScheme,
subject);
xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
virDomainFree(dom);
return event;
no_memory:
xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
if (localAddr) {
VIR_FREE(localAddr->service);
VIR_FREE(localAddr->node);
VIR_FREE(localAddr);
}
if (remoteAddr) {
VIR_FREE(remoteAddr->service);
VIR_FREE(remoteAddr->node);
VIR_FREE(remoteAddr);
}
if (subject) {
for (i = 0 ; i < subject->nidentity ; i++) {
VIR_FREE(subject->identities[i].type);
VIR_FREE(subject->identities[i].name);
}
VIR_FREE(subject->identities);
VIR_FREE(subject);
}
return NULL;
}
static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
remoteSecretOpen (virConnectPtr conn,
virConnectAuthPtr auth,
@ -8583,6 +8671,10 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
event = remoteDomainReadEventIOError(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS:
event = remoteDomainReadEventGraphics(conn, xdr);
break;
default:
DEBUG("Unexpected event proc %d", hdr->proc);
break;

View File

@ -3096,6 +3096,51 @@ xdr_remote_domain_event_io_error_msg (XDR *xdrs, remote_domain_event_io_error_ms
return TRUE;
}
bool_t
xdr_remote_domain_event_graphics_address (XDR *xdrs, remote_domain_event_graphics_address *objp)
{
if (!xdr_int (xdrs, &objp->family))
return FALSE;
if (!xdr_remote_nonnull_string (xdrs, &objp->node))
return FALSE;
if (!xdr_remote_nonnull_string (xdrs, &objp->service))
return FALSE;
return TRUE;
}
bool_t
xdr_remote_domain_event_graphics_identity (XDR *xdrs, remote_domain_event_graphics_identity *objp)
{
if (!xdr_remote_nonnull_string (xdrs, &objp->type))
return FALSE;
if (!xdr_remote_nonnull_string (xdrs, &objp->name))
return FALSE;
return TRUE;
}
bool_t
xdr_remote_domain_event_graphics_msg (XDR *xdrs, remote_domain_event_graphics_msg *objp)
{
char **objp_cpp0 = (char **) (void *) &objp->subject.subject_val;
if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
return FALSE;
if (!xdr_int (xdrs, &objp->phase))
return FALSE;
if (!xdr_remote_domain_event_graphics_address (xdrs, &objp->local))
return FALSE;
if (!xdr_remote_domain_event_graphics_address (xdrs, &objp->remote))
return FALSE;
if (!xdr_remote_nonnull_string (xdrs, &objp->authScheme))
return FALSE;
if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->subject.subject_len, REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX,
sizeof (remote_domain_event_graphics_identity), (xdrproc_t) xdr_remote_domain_event_graphics_identity))
return FALSE;
return TRUE;
}
bool_t
xdr_remote_procedure (XDR *xdrs, remote_procedure *objp)
{

View File

@ -1752,6 +1752,33 @@ struct remote_domain_event_io_error_msg {
int action;
};
typedef struct remote_domain_event_io_error_msg remote_domain_event_io_error_msg;
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
typedef struct remote_domain_event_graphics_address remote_domain_event_graphics_address;
#define REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX 20
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
typedef struct remote_domain_event_graphics_identity remote_domain_event_graphics_identity;
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;
struct {
u_int subject_len;
remote_domain_event_graphics_identity *subject_val;
} subject;
};
typedef struct remote_domain_event_graphics_msg remote_domain_event_graphics_msg;
#define REMOTE_PROGRAM 0x20008086
#define REMOTE_PROTOCOL_VERSION 1
@ -1928,6 +1955,7 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 170,
REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 171,
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 172,
REMOTE_PROC_DOMAIN_EVENT_GRAPHICS = 173,
};
typedef enum remote_procedure remote_procedure;
@ -2245,6 +2273,9 @@ extern bool_t xdr_remote_domain_event_reboot_msg (XDR *, remote_domain_event_re
extern bool_t xdr_remote_domain_event_rtc_change_msg (XDR *, remote_domain_event_rtc_change_msg*);
extern bool_t xdr_remote_domain_event_watchdog_msg (XDR *, remote_domain_event_watchdog_msg*);
extern bool_t xdr_remote_domain_event_io_error_msg (XDR *, remote_domain_event_io_error_msg*);
extern bool_t xdr_remote_domain_event_graphics_address (XDR *, remote_domain_event_graphics_address*);
extern bool_t xdr_remote_domain_event_graphics_identity (XDR *, remote_domain_event_graphics_identity*);
extern bool_t xdr_remote_domain_event_graphics_msg (XDR *, remote_domain_event_graphics_msg*);
extern bool_t xdr_remote_procedure (XDR *, remote_procedure*);
extern bool_t xdr_remote_message_type (XDR *, remote_message_type*);
extern bool_t xdr_remote_message_status (XDR *, remote_message_status*);
@ -2536,6 +2567,9 @@ extern bool_t xdr_remote_domain_event_reboot_msg ();
extern bool_t xdr_remote_domain_event_rtc_change_msg ();
extern bool_t xdr_remote_domain_event_watchdog_msg ();
extern bool_t xdr_remote_domain_event_io_error_msg ();
extern bool_t xdr_remote_domain_event_graphics_address ();
extern bool_t xdr_remote_domain_event_graphics_identity ();
extern bool_t xdr_remote_domain_event_graphics_msg ();
extern bool_t xdr_remote_procedure ();
extern bool_t xdr_remote_message_type ();
extern bool_t xdr_remote_message_status ();

View File

@ -1557,6 +1557,28 @@ struct remote_domain_event_io_error_msg {
int action;
};
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>;
};
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
@ -1752,7 +1774,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 170,
REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 171,
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 172
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 172,
REMOTE_PROC_DOMAIN_EVENT_GRAPHICS = 173
/*
* Notice how the entries are grouped in sets of 10 ?