[libvirt] [PATCH 13/13] Add domain events for graphics network clients

Daniel P. Berrange berrange at redhat.com
Fri Mar 19 15:39:01 UTC 2010


This introduces a new event type

   VIR_DOMAIN_EVENT_ID_GRAPHICS

The same event can be emitted in 3 scenarioes

  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 initailize 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 *alot* 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
---
 daemon/remote.c                              |   65 ++++++++++++++++++
 daemon/remote_dispatch_table.h               |    5 ++
 examples/domain-events/events-c/event-test.c |   51 ++++++++++++++-
 include/libvirt/libvirt.h.in                 |   41 +++++++++++
 src/conf/domain_event.c                      |   94 +++++++++++++++++++++++++-
 src/conf/domain_event.h                      |   15 ++++
 src/libvirt_private.syms                     |    2 +
 src/qemu/qemu_driver.c                       |   93 +++++++++++++++++++++++++
 src/qemu/qemu_monitor.c                      |   30 ++++++++
 src/qemu/qemu_monitor.h                      |   24 +++++++
 src/qemu/qemu_monitor_json.c                 |   74 ++++++++++++++++++++
 src/remote/remote_driver.c                   |   92 +++++++++++++++++++++++++
 src/remote/remote_protocol.c                 |   45 ++++++++++++
 src/remote/remote_protocol.h                 |   34 +++++++++
 src/remote/remote_protocol.x                 |   26 +++++++-
 15 files changed, 688 insertions(+), 3 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index e2912a1..888be48 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -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);
diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h
index 31d652d..6459038 100644
--- a/daemon/remote_dispatch_table.h
+++ b/daemon/remote_dispatch_table.h
@@ -857,3 +857,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,
+},
diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c
index bb3c7bb..53a3195 100644
--- a/examples/domain-events/events-c/event-test.c
+++ b/examples/domain-events/events-c/event-test.c
@@ -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");
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index bffd9ed..4205b91 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1870,6 +1870,46 @@ typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
                                                      int action,
                                                      void *opaque);
 
+typedef enum {
+    VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
+    VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
+    VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
+} virDomainEventGraphicsPhase;
+
+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);
+
+
+
 /* Use this to cast the event specific callback into the generic one
  * for use for virDomainEventRegister */
 #define VIR_DOMAIN_EVENT_CALLBACK(cb) ((virConnectDomainEventGenericCallback)(cb))
@@ -1881,6 +1921,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
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 77b52ef..df3cced 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -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;
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index dbf9288..16c7870 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -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);
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4578762..0829eea 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -222,6 +222,8 @@ virDomainEventWatchdogNewFromDom;
 virDomainEventWatchdogNewFromObj;
 virDomainEventIOErrorNewFromDom;
 virDomainEventIOErrorNewFromObj;
+virDomainEventGraphicsNewFromDom;
+virDomainEventGraphicsNewFromObj;
 virDomainEventFree;
 virDomainEventDispatchDefaultFunc;
 virDomainEventDispatch;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 71cca5c..5dece1b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -984,6 +984,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,
@@ -991,6 +1083,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
     .domainRTCChange = qemuHandleDomainRTCChange,
     .domainWatchdog = qemuHandleDomainWatchdog,
     .domainIOError = qemuHandleDomainIOError,
+    .domainGraphics = qemuHandleDomainGraphics,
 };
 
 static int
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index f320df9..28d652e 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -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;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 64ae153..5d62177 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -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);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e2d7744..d216239 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -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)
 {
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 068ad9b..426e620 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -6998,6 +6998,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,
@@ -8527,6 +8615,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;
diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c
index 79dfb98..6571d88 100644
--- a/src/remote/remote_protocol.c
+++ b/src/remote/remote_protocol.c
@@ -3073,6 +3073,51 @@ xdr_remote_domain_event_io_error_msg (XDR *xdrs, remote_domain_event_io_error_ms
 }
 
 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)
 {
 
diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h
index cddd284..33c8674 100644
--- a/src/remote/remote_protocol.h
+++ b/src/remote/remote_protocol.h
@@ -1739,6 +1739,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
 
@@ -1913,6 +1940,7 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 168,
         REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 169,
         REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 170,
+        REMOTE_PROC_DOMAIN_EVENT_GRAPHICS = 171,
 };
 typedef enum remote_procedure remote_procedure;
 
@@ -2228,6 +2256,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*);
@@ -2517,6 +2548,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 ();
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 3cdc99b..23ba619 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -1546,6 +1546,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. */
@@ -1738,7 +1760,9 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_EVENT_REBOOT = 167,
     REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 168,
     REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 169,
-    REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 170
+    REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 170,
+
+    REMOTE_PROC_DOMAIN_EVENT_GRAPHICS = 171
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
-- 
1.6.6.1




More information about the libvir-list mailing list