]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Add domain events for graphics network clients
authorDaniel P. Berrange <berrange@redhat.com>
Fri, 19 Mar 2010 13:27:45 +0000 (13:27 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 26 Mar 2010 13:53:20 +0000 (13:53 +0000)
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

16 files changed:
daemon/remote.c
daemon/remote_dispatch_table.h
examples/domain-events/events-c/event-test.c
include/libvirt/libvirt.h.in
python/generator.py
src/conf/domain_event.c
src/conf/domain_event.h
src/libvirt_private.syms
src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/remote/remote_driver.c
src/remote/remote_protocol.c
src/remote/remote_protocol.h
src/remote/remote_protocol.x

index 885e9d4bf52f856daec073e69b9b8a1b9edfa7bd..005af422ed2aa8402500e63bf5fbb582628aac7c 100644 (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);
index 019212d61cd385a928ae88cf0f49d06375a06be7..f1b18539097ab4ade9fce0072b6a8704ba5bbd48 100644 (file)
     .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,
+},
index bb3c7bbda6b0acaefeddf816d5c3727184f090e5..53a319516692858f2668a2e245cbd9b5c8f120cb 100644 (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");
index 9c9076814774a7a85c26178956af2c3c8a9bd3c7..936382104e06cc44eebd5608ed4a50e55d05ecec 100644 (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
index 73a8b2b8a58a615d05881792c0522f7a3688d833..acc8c90cf7f2f53640d094e6211b9c7fc0744cfb 100755 (executable)
@@ -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",
 }
 
index 839c99bc033d21f122ca0eaa02a75401302e8109..41c70fc6e1af859b102be6a2945809dd470d7801 100644 (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;
index 652c93744ec73249f896a23ef127078bfec71314..f72ac5822fe930dfa9f3e17e2e42836fef06fcd7 100644 (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);
 
index f3dccd8812af978f1ccdb01c4a64e6ecd43f8de6..cf6670dd06a2d1ceaba69d0677507f8a0925f6ce 100644 (file)
@@ -222,6 +222,8 @@ virDomainEventWatchdogNewFromDom;
 virDomainEventWatchdogNewFromObj;
 virDomainEventIOErrorNewFromDom;
 virDomainEventIOErrorNewFromObj;
+virDomainEventGraphicsNewFromDom;
+virDomainEventGraphicsNewFromObj;
 virDomainEventFree;
 virDomainEventDispatchDefaultFunc;
 virDomainEventDispatch;
index 5898eda71caf1085dd24ed919f1bdc9ff508777c..214324def01ff6c1ab434c9b2539a19e2a89dcfe 100644 (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
index baf5bd8e4d594deebdbbf79a3d1dcc3ce6b44186..f998d77d7b5b7335ecde0a583842b87994e011d1 100644 (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;
index ad5316f853043d8b0133e0a5907af30018286d22..07773bd3cdd9579b3add054a4f98af001442870c 100644 (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);
index 30ae80f1be2715fae900cb914372d65faa7621af..3901d46674ebac840e03d1e2858e8c5a2913562d 100644 (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)
 {
index 91b3a832e82970cc165858175ccaefb5b64a382e..e28a364dec84f03adeeaf47ba80787712bf21c4f 100644 (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;
index 66fcea716615e030eb813a532abf6a4421da9693..dc5222b61c500b18d588c5f0950206b0a3aa4924 100644 (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)
 {
index d49e8dcbab8b34a5dd714f0135f937a99f12d4a9..fa223ed9ef8493ed1765c5dc1ec053516f7ce8fa 100644 (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 ();
index 24be558d997ed2005ab0dd73334f6e485773b5b5..394783708c8c35c1607fd1a42d5bd724eae02b0b 100644 (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 ?