[PATCH 04/15] Break virNetServer into virNetSubServers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Each subserver has its own RPC programs, services, workers, keepalive,
clients etc.  Hence (possible) multiple subservers are properly
separated.

The part in remote.c is just mechanical, the same applies to most of the
code movement from virnetserver.c to virnetsubserver.c.

Signed-off-by: Martin Kletzander <mkletzan@xxxxxxxxxx>
---
 daemon/libvirtd.c                  |  47 +-
 daemon/remote.c                    | 194 ++++-----
 po/POTFILES.in                     |   1 +
 src/Makefile.am                    |   1 +
 src/libvirt_remote.syms            |  16 +-
 src/locking/lock_daemon.c          |  40 +-
 src/locking/lock_daemon_dispatch.c |  18 +-
 src/lxc/lxc_controller.c           |  18 +-
 src/rpc/gendispatch.pl             |  13 +-
 src/rpc/virnetserver.c             | 859 +++++++++++++------------------------
 src/rpc/virnetserver.h             |  61 +--
 src/rpc/virnetserverprogram.c      |  12 +-
 src/rpc/virnetserverprogram.h      |   9 +-
 src/rpc/virnetsubserver.c          | 662 ++++++++++++++++++++++++++++
 src/rpc/virnetsubserver.h          |  76 ++++
 15 files changed, 1263 insertions(+), 764 deletions(-)
 create mode 100644 src/rpc/virnetsubserver.c
 create mode 100644 src/rpc/virnetsubserver.h

diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 107b88d..e209e93 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1,7 +1,7 @@
 /*
  * libvirtd.c: daemon start of day, guest process & i/o management
  *
- * Copyright (C) 2006-2014 Red Hat, Inc.
+ * Copyright (C) 2006-2015 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -492,14 +492,14 @@ daemonSetupNetworking(virNetServerPtr srv,
             goto error;
     }

-    if (virNetServerAddService(srv, svc,
+    if (virNetServerAddService(srv, 0, svc,
                                config->mdns_adv && !ipsock ?
                                "_libvirt._tcp" :
                                NULL) < 0)
         goto error;

     if (svcRO &&
-        virNetServerAddService(srv, svcRO, NULL) < 0)
+        virNetServerAddService(srv, 0, svcRO, NULL) < 0)
         goto error;

     if (ipsock) {
@@ -517,7 +517,7 @@ daemonSetupNetworking(virNetServerPtr srv,
                                                      config->max_client_requests)))
                 goto error;

-            if (virNetServerAddService(srv, svcTCP,
+            if (virNetServerAddService(srv, 0, svcTCP,
                                        config->mdns_adv ? "_libvirt._tcp" : NULL) < 0)
                 goto error;
         }
@@ -559,7 +559,7 @@ daemonSetupNetworking(virNetServerPtr srv,
                 virObjectUnref(ctxt);
                 goto error;
             }
-            if (virNetServerAddService(srv, svcTLS,
+            if (virNetServerAddService(srv, 0, svcTLS,
                                        config->mdns_adv &&
                                        !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0)
                 goto error;
@@ -1334,19 +1334,24 @@ int main(int argc, char **argv) {
         goto cleanup;
     }

-    if (!(srv = virNetServerNew(config->min_workers,
-                                config->max_workers,
-                                config->prio_workers,
-                                config->max_clients,
-                                config->max_anonymous_clients,
-                                config->keepalive_interval,
-                                config->keepalive_count,
-                                !!config->keepalive_required,
-                                config->mdns_adv ? config->mdns_name : NULL,
-                                remoteClientInitHook,
-                                NULL,
-                                remoteClientFreeFunc,
-                                NULL))) {
+    if (!(srv = virNetServerNew(config->mdns_adv ? config->mdns_name : NULL))) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
+    if (virNetServerAddSubServer(srv,
+                                 config->min_workers,
+                                 config->max_workers,
+                                 config->prio_workers,
+                                 config->max_clients,
+                                 config->max_anonymous_clients,
+                                 config->keepalive_interval,
+                                 config->keepalive_count,
+                                 !!config->keepalive_required,
+                                 remoteClientInitHook,
+                                 NULL,
+                                 remoteClientFreeFunc,
+                                 NULL) < 0) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
     }
@@ -1374,7 +1379,7 @@ int main(int argc, char **argv) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
     }
-    if (virNetServerAddProgram(srv, remoteProgram) < 0) {
+    if (virNetServerAddProgram(srv, 0, remoteProgram) < 0) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
     }
@@ -1386,7 +1391,7 @@ int main(int argc, char **argv) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
     }
-    if (virNetServerAddProgram(srv, lxcProgram) < 0) {
+    if (virNetServerAddProgram(srv, 0, lxcProgram) < 0) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
     }
@@ -1398,7 +1403,7 @@ int main(int argc, char **argv) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
     }
-    if (virNetServerAddProgram(srv, qemuProgram) < 0) {
+    if (virNetServerAddProgram(srv, 0, qemuProgram) < 0) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
     }
diff --git a/daemon/remote.c b/daemon/remote.c
index 3a3f168..41d75cc 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1290,7 +1290,7 @@ void *remoteClientInitHook(virNetServerClientPtr client,
 /*----- Functions. -----*/

 static int
-remoteDispatchConnectOpen(virNetServerPtr server,
+remoteDispatchConnectOpen(virNetSubServerPtr subserver,
                           virNetServerClientPtr client,
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                           virNetMessageErrorPtr rerr,
@@ -1309,7 +1309,8 @@ remoteDispatchConnectOpen(virNetServerPtr server,
         goto cleanup;
     }

-    if (virNetServerKeepAliveRequired(server) && !priv->keepalive_supported) {
+    if (virNetSubServerKeepAliveRequired(subserver) &&
+        !priv->keepalive_supported) {
         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("keepalive support is required to connect"));
         goto cleanup;
@@ -1343,7 +1344,7 @@ remoteDispatchConnectOpen(virNetServerPtr server,


 static int
-remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectClose(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                            virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
@@ -1354,7 +1355,7 @@ remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetSchedulerType(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
@@ -1548,7 +1549,7 @@ remoteDeserializeTypedParameters(remote_typed_param *args_params_val,
 }

 static int
-remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetSchedulerParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr,
@@ -1598,7 +1599,7 @@ remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUS
 }

 static int
-remoteDispatchConnectListAllDomains(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectListAllDomains(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -1656,7 +1657,7 @@ remoteDispatchConnectListAllDomains(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetSchedulerParametersFlags(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                 virNetMessageErrorPtr rerr,
@@ -1707,7 +1708,7 @@ remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE
 }

 static int
-remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMemoryStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                 virNetMessageErrorPtr rerr,
@@ -1765,7 +1766,7 @@ remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainBlockPeek(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                               virNetServerClientPtr client ATTRIBUTE_UNUSED,
                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                               virNetMessageErrorPtr rerr,
@@ -1819,7 +1820,7 @@ remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainBlockStatsFlags(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -1882,7 +1883,7 @@ remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMemoryPeek(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                virNetMessageErrorPtr rerr,
@@ -1934,7 +1935,7 @@ remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetSecurityLabel(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
@@ -1978,7 +1979,7 @@ remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetSecurityLabelList(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr,
@@ -2037,7 +2038,7 @@ remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED
 }

 static int
-remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetSecurityModel(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
@@ -2076,7 +2077,7 @@ remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetVcpuPinInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
@@ -2141,7 +2142,7 @@ remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainPinEmulator(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainPinEmulator(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client,
                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                 virNetMessageErrorPtr rerr,
@@ -2177,7 +2178,7 @@ remoteDispatchDomainPinEmulator(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetEmulatorPinInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
@@ -2226,7 +2227,7 @@ remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetVcpus(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                              virNetMessageErrorPtr rerr,
@@ -2307,7 +2308,7 @@ remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetIOThreadInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetIOThreadInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -2379,7 +2380,7 @@ remoteDispatchDomainGetIOThreadInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigratePrepare(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
@@ -2434,7 +2435,7 @@ remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigratePrepare2(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -2486,7 +2487,7 @@ remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetMemoryParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                         virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr,
@@ -2548,7 +2549,7 @@ remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetNumaParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetNumaParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
@@ -2610,7 +2611,7 @@ remoteDispatchDomainGetNumaParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetBlkioParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
@@ -2672,7 +2673,7 @@ remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetCPUStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                               virNetServerClientPtr client ATTRIBUTE_UNUSED,
                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                               virNetMessageErrorPtr rerr,
@@ -2744,7 +2745,7 @@ remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetMemoryStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                  virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                  virNetMessageErrorPtr rerr,
@@ -2816,7 +2817,7 @@ remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetBlockJobInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -2856,7 +2857,7 @@ remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetBlockIoTune(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetBlockIoTune(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                    virNetMessagePtr hdr ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
@@ -2920,7 +2921,7 @@ remoteDispatchDomainGetBlockIoTune(virNetServerPtr server ATTRIBUTE_UNUSED,
 /*-------------------------------------------------------------*/

 static int
-remoteDispatchAuthList(virNetServerPtr server,
+remoteDispatchAuthList(virNetSubServerPtr subserver,
                        virNetServerClientPtr client,
                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                        virNetMessageErrorPtr rerr,
@@ -2950,7 +2951,7 @@ remoteDispatchAuthList(virNetServerPtr server,
                 goto cleanup;
             VIR_INFO("Bypass polkit auth for privileged client %s", ident);
             virNetServerClientSetAuth(client, 0);
-            virNetServerTrackCompletedAuth(server);
+            virNetSubServerTrackCompletedAuth(subserver);
             auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
             VIR_FREE(ident);
         }
@@ -2989,7 +2990,7 @@ remoteDispatchAuthList(virNetServerPtr server,
  * and gives the client a list of allowed mechanisms to choose
  */
 static int
-remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchAuthSaslInit(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client,
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                            virNetMessageErrorPtr rerr,
@@ -3066,7 +3067,7 @@ remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
  * Returns 0 if ok, -1 on error, -2 if rejected
  */
 static int
-remoteSASLFinish(virNetServerPtr server,
+remoteSASLFinish(virNetSubServerPtr subserver,
                  virNetServerClientPtr client)
 {
     const char *identity;
@@ -3092,7 +3093,7 @@ remoteSASLFinish(virNetServerPtr server,
         return -2;

     virNetServerClientSetAuth(client, 0);
-    virNetServerTrackCompletedAuth(server);
+    virNetSubServerTrackCompletedAuth(subserver);
     virNetServerClientSetSASLSession(client, priv->sasl);

     VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client));
@@ -3114,7 +3115,7 @@ remoteSASLFinish(virNetServerPtr server,
  * This starts the SASL authentication negotiation.
  */
 static int
-remoteDispatchAuthSaslStart(virNetServerPtr server,
+remoteDispatchAuthSaslStart(virNetSubServerPtr subserver,
                             virNetServerClientPtr client,
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                             virNetMessageErrorPtr rerr,
@@ -3172,7 +3173,7 @@ remoteDispatchAuthSaslStart(virNetServerPtr server,
         ret->complete = 0;
     } else {
         /* Check username whitelist ACL */
-        if ((err = remoteSASLFinish(server, client)) < 0) {
+        if ((err = remoteSASLFinish(subserver, client)) < 0) {
             if (err == -2)
                 goto authdeny;
             else
@@ -3212,7 +3213,7 @@ remoteDispatchAuthSaslStart(virNetServerPtr server,


 static int
-remoteDispatchAuthSaslStep(virNetServerPtr server,
+remoteDispatchAuthSaslStep(virNetSubServerPtr subserver,
                            virNetServerClientPtr client,
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                            virNetMessageErrorPtr rerr,
@@ -3270,7 +3271,7 @@ remoteDispatchAuthSaslStep(virNetServerPtr server,
         ret->complete = 0;
     } else {
         /* Check username whitelist ACL */
-        if ((err = remoteSASLFinish(server, client)) < 0) {
+        if ((err = remoteSASLFinish(subserver, client)) < 0) {
             if (err == -2)
                 goto authdeny;
             else
@@ -3309,7 +3310,7 @@ remoteDispatchAuthSaslStep(virNetServerPtr server,
 }
 #else
 static int
-remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchAuthSaslInit(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                            virNetMessageErrorPtr rerr,
@@ -3322,7 +3323,7 @@ remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
     return -1;
 }
 static int
-remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchAuthSaslStart(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                             virNetMessageErrorPtr rerr,
@@ -3336,7 +3337,7 @@ remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
     return -1;
 }
 static int
-remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchAuthSaslStep(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                            virNetMessageErrorPtr rerr,
@@ -3354,7 +3355,7 @@ remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchAuthPolkit(virNetServerPtr server,
+remoteDispatchAuthPolkit(virNetSubServerPtr subserver,
                          virNetServerClientPtr client,
                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                          virNetMessageErrorPtr rerr,
@@ -3414,7 +3415,7 @@ remoteDispatchAuthPolkit(virNetServerPtr server,
     ret->complete = 1;

     virNetServerClientSetAuth(client, 0);
-    virNetServerTrackCompletedAuth(server);
+    virNetSubServerTrackCompletedAuth(subserver);
     virMutexUnlock(&priv->lock);

     return 0;
@@ -3437,13 +3438,12 @@ remoteDispatchAuthPolkit(virNetServerPtr server,
     goto error;
 }

-
 /***************************************************************
  *     NODE INFO APIS
  **************************************************************/

 static int
-remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeDeviceGetParent(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                   virNetMessageErrorPtr rerr,
@@ -3494,7 +3494,7 @@ remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
  * Register / deregister events
  ***************************/
 static int
-remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectDomainEventRegister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -3557,7 +3557,7 @@ remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED
 }

 static int
-remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectDomainEventDeregister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                            virNetServerClientPtr client,
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -3642,7 +3642,7 @@ remoteDispatchObjectEventSend(virNetServerClientPtr client,
 }

 static int
-remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchSecretGetValue(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                              virNetMessageErrorPtr rerr,
@@ -3680,7 +3680,7 @@ remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetState(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                              virNetMessageErrorPtr rerr,
@@ -3719,7 +3719,7 @@ remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
  * VIR_DRV_SUPPORTS_FEATURE(VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK),
  * and must not mix the two styles.  */
 static int
-remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectDomainEventRegisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                             virNetServerClientPtr client,
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -3793,7 +3793,7 @@ remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNU


 static int
-remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectDomainEventCallbackRegisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                     virNetServerClientPtr client,
                                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                     virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -3870,7 +3870,7 @@ remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRI


 static int
-remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectDomainEventDeregisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                               virNetServerClientPtr client,
                                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                               virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -3928,7 +3928,7 @@ remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_U


 static int
-remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                       virNetServerClientPtr client,
                                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                       virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -3974,7 +3974,7 @@ remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetServerPtr server ATT


 static int
-qemuDispatchDomainMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
+qemuDispatchDomainMonitorCommand(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                  virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                  virNetMessageErrorPtr rerr,
@@ -4009,7 +4009,7 @@ qemuDispatchDomainMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigrateBegin3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                   virNetMessageErrorPtr rerr,
@@ -4060,7 +4060,7 @@ remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigratePrepare3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -4116,7 +4116,7 @@ remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigratePerform3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -4171,7 +4171,7 @@ remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigrateFinish3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
@@ -4224,7 +4224,7 @@ remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigrateConfirm3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -4259,7 +4259,7 @@ remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
 }


-static int remoteDispatchConnectSupportsFeature(virNetServerPtr server ATTRIBUTE_UNUSED,
+static int remoteDispatchConnectSupportsFeature(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                 virNetServerClientPtr client,
                                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                 virNetMessageErrorPtr rerr,
@@ -4310,7 +4310,7 @@ static int remoteDispatchConnectSupportsFeature(virNetServerPtr server ATTRIBUTE


 static int
-remoteDispatchDomainOpenGraphics(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainOpenGraphics(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                  virNetMessagePtr msg,
                                  virNetMessageErrorPtr rerr,
@@ -4351,7 +4351,7 @@ remoteDispatchDomainOpenGraphics(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainOpenGraphicsFd(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainOpenGraphicsFd(virNetSubServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                    virNetMessagePtr msg,
                                    virNetMessageErrorPtr rerr,
@@ -4394,7 +4394,7 @@ remoteDispatchDomainOpenGraphicsFd(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetInterfaceParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr,
@@ -4457,7 +4457,7 @@ remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server ATTRIBUTE_UNUS
 }

 static int
-remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetCPUStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                 virNetMessagePtr hdr ATTRIBUTE_UNUSED,
                                 virNetMessageErrorPtr rerr,
@@ -4528,7 +4528,7 @@ remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetDiskErrors(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client,
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                   virNetMessageErrorPtr rerr,
@@ -4588,7 +4588,7 @@ remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainListAllSnapshots(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainListAllSnapshots(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
@@ -4651,7 +4651,7 @@ remoteDispatchDomainListAllSnapshots(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainSnapshotListAllChildren(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainSnapshotListAllChildren(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                             virNetServerClientPtr client,
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr,
@@ -4719,7 +4719,7 @@ remoteDispatchDomainSnapshotListAllChildren(virNetServerPtr server ATTRIBUTE_UNU
 }

 static int
-remoteDispatchConnectListAllStoragePools(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectListAllStoragePools(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr,
@@ -4777,7 +4777,7 @@ remoteDispatchConnectListAllStoragePools(virNetServerPtr server ATTRIBUTE_UNUSED
 }

 static int
-remoteDispatchStoragePoolListAllVolumes(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchStoragePoolListAllVolumes(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                         virNetServerClientPtr client,
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr,
@@ -4840,7 +4840,7 @@ remoteDispatchStoragePoolListAllVolumes(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchConnectListAllNetworks(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectListAllNetworks(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
@@ -4898,7 +4898,7 @@ remoteDispatchConnectListAllNetworks(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchConnectListAllInterfaces(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectListAllInterfaces(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
@@ -4956,7 +4956,7 @@ remoteDispatchConnectListAllInterfaces(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchConnectListAllNodeDevices(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectListAllNodeDevices(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                         virNetServerClientPtr client,
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr,
@@ -5014,7 +5014,7 @@ remoteDispatchConnectListAllNodeDevices(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchConnectListAllNWFilters(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectListAllNWFilters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
@@ -5072,7 +5072,7 @@ remoteDispatchConnectListAllNWFilters(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchConnectListAllSecrets(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectListAllSecrets(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
@@ -5130,7 +5130,7 @@ remoteDispatchConnectListAllSecrets(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetMemoryParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
@@ -5187,7 +5187,7 @@ remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchNodeGetCPUMap(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetCPUMap(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                             virNetMessageErrorPtr rerr,
@@ -5234,7 +5234,7 @@ remoteDispatchNodeGetCPUMap(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED,
+lxcDispatchDomainOpenNamespace(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                virNetMessageErrorPtr rerr,
@@ -5284,7 +5284,7 @@ lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainGetJobStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetJobStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client,
                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                 virNetMessageErrorPtr rerr,
@@ -5334,7 +5334,7 @@ remoteDispatchDomainGetJobStats(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigrateBegin3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                         virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr,
@@ -5391,7 +5391,7 @@ remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
 }

 static int
-remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigratePrepare3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                           virNetMessageErrorPtr rerr,
@@ -5451,7 +5451,7 @@ remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSE
 }

 static int
-remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigratePrepareTunnel3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                 virNetServerClientPtr client,
                                                 virNetMessagePtr msg,
                                                 virNetMessageErrorPtr rerr,
@@ -5521,7 +5521,7 @@ remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE


 static int
-remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigratePerform3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                           virNetMessageErrorPtr rerr,
@@ -5582,7 +5582,7 @@ remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSE


 static int
-remoteDispatchDomainMigrateFinish3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigrateFinish3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr,
@@ -5642,7 +5642,7 @@ remoteDispatchDomainMigrateFinish3Params(virNetServerPtr server ATTRIBUTE_UNUSED


 static int
-remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainMigrateConfirm3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                           virNetMessageErrorPtr rerr,
@@ -5693,7 +5693,7 @@ remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSE


 static int
-remoteDispatchConnectGetCPUModelNames(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectGetCPUModelNames(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
@@ -5745,7 +5745,7 @@ remoteDispatchConnectGetCPUModelNames(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainCreateXMLWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainCreateXMLWithFiles(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
@@ -5792,7 +5792,7 @@ remoteDispatchDomainCreateXMLWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
 }


-static int remoteDispatchDomainCreateWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
+static int remoteDispatchDomainCreateWithFiles(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                virNetServerClientPtr client,
                                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                virNetMessageErrorPtr rerr,
@@ -5843,7 +5843,7 @@ static int remoteDispatchDomainCreateWithFiles(virNetServerPtr server ATTRIBUTE_


 static int
-remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectNetworkEventRegisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                              virNetServerClientPtr client,
                                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                              virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -5920,7 +5920,7 @@ remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UN


 static int
-remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectNetworkEventDeregisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                virNetServerClientPtr client,
                                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -5966,7 +5966,7 @@ remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_


 static int
-qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+qemuDispatchConnectDomainMonitorEventRegister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                               virNetServerClientPtr client,
                                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                               virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -6038,7 +6038,7 @@ qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_U


 static int
-qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+qemuDispatchConnectDomainMonitorEventDeregister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                                 virNetServerClientPtr client,
                                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                 virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
@@ -6084,7 +6084,7 @@ qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE
 }

 static int
-remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetTime(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client,
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                             virNetMessageErrorPtr rerr,
@@ -6122,7 +6122,7 @@ remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchNodeGetFreePages(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetFreePages(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client,
                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                virNetMessageErrorPtr rerr,
@@ -6235,7 +6235,7 @@ remoteSerializeDHCPLease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLea


 static int
-remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNetworkGetDHCPLeases(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
@@ -6303,7 +6303,7 @@ remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchConnectGetAllDomainStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
@@ -6389,7 +6389,7 @@ remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchNodeAllocPages(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchNodeAllocPages(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client,
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                              virNetMessageErrorPtr rerr,
@@ -6426,7 +6426,7 @@ remoteDispatchNodeAllocPages(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-remoteDispatchDomainGetFSInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainGetFSInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                               virNetServerClientPtr client,
                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                               virNetMessageErrorPtr rerr,
@@ -6620,7 +6620,7 @@ remoteSerializeDomainInterface(virDomainInterfacePtr *ifaces,


 static int
-remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED,
+remoteDispatchDomainInterfaceAddresses(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
diff --git a/po/POTFILES.in b/po/POTFILES.in
index dd06ab3..af07e09 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -140,6 +140,7 @@ src/rpc/virnetservermdns.c
 src/rpc/virnetserverprogram.c
 src/rpc/virnetserverservice.c
 src/rpc/virnetsshsession.c
+src/rpc/virnetsubserver.c
 src/rpc/virnettlscontext.c
 src/secret/secret_driver.c
 src/security/security_apparmor.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 6d1b4fb..d6245bd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2487,6 +2487,7 @@ libvirt_net_rpc_server_la_SOURCES = \
 	rpc/virnetserverservice.h rpc/virnetserverservice.c \
 	rpc/virnetserverclient.h rpc/virnetserverclient.c \
 	rpc/virnetservermdns.h rpc/virnetservermdns.c \
+	rpc/virnetsubserver.h rpc/virnetsubserver.c \
 	rpc/virnetserver.h rpc/virnetserver.c
 libvirt_net_rpc_server_la_CFLAGS = \
 			$(AVAHI_CFLAGS) \
diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms
index 6b520b5..f7cf226 100644
--- a/src/libvirt_remote.syms
+++ b/src/libvirt_remote.syms
@@ -83,8 +83,8 @@ virNetServerAddShutdownInhibition;
 virNetServerAddSignalHandler;
 virNetServerAutoShutdown;
 virNetServerClose;
+virNetServerGetSubServer;
 virNetServerIsPrivileged;
-virNetServerKeepAliveRequired;
 virNetServerNew;
 virNetServerNewPostExecRestart;
 virNetServerPreExecRestart;
@@ -205,6 +205,20 @@ virNetSocketUpdateIOCallback;
 virNetSocketWrite;


+# rpc/virnetsubserver.h
+virNetSubServerAddProgram;
+virNetSubServerAddService;
+virNetSubServerClose;
+virNetSubServerHasClients;
+virNetSubServerKeepAliveRequired;
+virNetSubServerNew;
+virNetSubServerPreExecRestart;
+virNetSubServerProcessClients;
+virNetSubServerTrackCompletedAuth;
+virNetSubServerTrackPendingAuth;
+virNetSubServerUpdateServices;
+
+
 # Let emacs know we want case-insensitive sorting
 # Local Variables:
 # sort-fold-case: t
diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c
index bb165c0..b3c5873 100644
--- a/src/locking/lock_daemon.c
+++ b/src/locking/lock_daemon.c
@@ -146,13 +146,17 @@ virLockDaemonNew(virLockDaemonConfigPtr config, bool privileged)
         return NULL;
     }

-    if (!(lockd->srv = virNetServerNew(1, 1, 0, config->max_clients,
-                                       config->max_clients, -1, 0,
-                                       false, NULL,
-                                       virLockDaemonClientNew,
-                                       virLockDaemonClientPreExecRestart,
-                                       virLockDaemonClientFree,
-                                       (void*)(intptr_t)(privileged ? 0x1 : 0x0))))
+    if (!(lockd->srv = virNetServerNew(NULL)))
+        goto error;
+
+    if (virNetServerAddSubServer(lockd->srv, 1, 1, 0,
+                                 config->max_clients,
+                                 config->max_clients,
+                                 -1, 0, false,
+                                 virLockDaemonClientNew,
+                                 virLockDaemonClientPreExecRestart,
+                                 virLockDaemonClientFree,
+                                 (void*)(intptr_t)(privileged ? 0x1 : 0x0)) < 0)
         goto error;

     if (!(lockd->lockspaces = virHashCreate(VIR_LOCK_DAEMON_NUM_LOCKSPACES,
@@ -236,14 +240,18 @@ virLockDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
         goto error;
     }

-    if (!(lockd->srv = virNetServerNewPostExecRestart(child,
-                                                      virLockDaemonClientNew,
-                                                      virLockDaemonClientNewPostExecRestart,
-                                                      virLockDaemonClientPreExecRestart,
-                                                      virLockDaemonClientFree,
-                                                      (void*)(intptr_t)(privileged ? 0x1 : 0x0))))
+    if (!(lockd->srv = virNetServerNewPostExecRestart(child)))
         goto error;

+    if (virNetServerAddSubServerPostExec(lockd->srv,
+                                         virLockDaemonClientNew,
+                                         virLockDaemonClientNewPostExecRestart,
+                                         virLockDaemonClientPreExecRestart,
+                                         virLockDaemonClientFree,
+                                         (void*)(intptr_t)(privileged ? 0x1 : 0x0)) < 0)
+        goto error;
+
+
     return lockd;

  error:
@@ -581,7 +589,7 @@ virLockDaemonSetupNetworkingSystemD(virNetServerPtr srv)
                                          false, 0, 1)))
         return -1;

-    if (virNetServerAddService(srv, svc, NULL) < 0) {
+    if (virNetServerAddService(srv, 0, svc, NULL) < 0) {
         virObjectUnref(svc);
         return -1;
     }
@@ -603,7 +611,7 @@ virLockDaemonSetupNetworkingNative(virNetServerPtr srv, const char *sock_path)
                                            false, 0, 1)))
         return -1;

-    if (virNetServerAddService(srv, svc, NULL) < 0) {
+    if (virNetServerAddService(srv, 0, svc, NULL) < 0) {
         virObjectUnref(svc);
         return -1;
     }
@@ -1366,7 +1374,7 @@ int main(int argc, char **argv) {
         ret = VIR_LOCK_DAEMON_ERR_INIT;
         goto cleanup;
     }
-    if (virNetServerAddProgram(lockDaemon->srv, lockProgram) < 0) {
+    if (virNetServerAddProgram(lockDaemon->srv, 0, lockProgram) < 0) {
         ret = VIR_LOCK_DAEMON_ERR_INIT;
         goto cleanup;
     }
diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c
index a7cee9d..ae59d28 100644
--- a/src/locking/lock_daemon_dispatch.c
+++ b/src/locking/lock_daemon_dispatch.c
@@ -1,7 +1,7 @@
 /*
  * lock_daemon_dispatch.c: lock management daemon dispatch
  *
- * Copyright (C) 2006-2012 Red Hat, Inc.
+ * Copyright (C) 2006-2012, 2014 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -38,7 +38,7 @@ VIR_LOG_INIT("locking.lock_daemon_dispatch");
 #include "lock_daemon_dispatch_stubs.h"

 static int
-virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchAcquireResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                             virNetServerClientPtr client,
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr,
@@ -98,7 +98,7 @@ virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNU


 static int
-virLockSpaceProtocolDispatchCreateResource(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchCreateResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                            virNetServerClientPtr client,
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr,
@@ -147,7 +147,7 @@ virLockSpaceProtocolDispatchCreateResource(virNetServerPtr server ATTRIBUTE_UNUS


 static int
-virLockSpaceProtocolDispatchDeleteResource(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchDeleteResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                            virNetServerClientPtr client,
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr,
@@ -196,7 +196,7 @@ virLockSpaceProtocolDispatchDeleteResource(virNetServerPtr server ATTRIBUTE_UNUS


 static int
-virLockSpaceProtocolDispatchNew(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchNew(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client,
                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                 virNetMessageErrorPtr rerr,
@@ -252,7 +252,7 @@ virLockSpaceProtocolDispatchNew(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-virLockSpaceProtocolDispatchRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchRegister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
@@ -298,7 +298,7 @@ virLockSpaceProtocolDispatchRegister(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-virLockSpaceProtocolDispatchReleaseResource(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchReleaseResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                             virNetServerClientPtr client,
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr,
@@ -349,7 +349,7 @@ virLockSpaceProtocolDispatchReleaseResource(virNetServerPtr server ATTRIBUTE_UNU


 static int
-virLockSpaceProtocolDispatchRestrict(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchRestrict(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
@@ -388,7 +388,7 @@ virLockSpaceProtocolDispatchRestrict(virNetServerPtr server ATTRIBUTE_UNUSED,


 static int
-virLockSpaceProtocolDispatchCreateLockSpace(virNetServerPtr server ATTRIBUTE_UNUSED,
+virLockSpaceProtocolDispatchCreateLockSpace(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
                                             virNetServerClientPtr client,
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr,
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 2b5c9da..105a3dd 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2014 Red Hat, Inc.
+ * Copyright (C) 2010-2015 Red Hat, Inc.
  * Copyright IBM Corp. 2008
  *
  * lxc_controller.c: linux container process controller
@@ -854,13 +854,13 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl)
                     LXC_STATE_DIR, ctrl->name) < 0)
         return -1;

-    if (!(ctrl->server = virNetServerNew(0, 0, 0, 1,
-                                         0, -1, 0, false,
-                                         NULL,
-                                         virLXCControllerClientPrivateNew,
-                                         NULL,
-                                         virLXCControllerClientPrivateFree,
-                                         ctrl)))
+    if (!(ctrl->server = virNetServerNew(NULL)))
+        goto error;
+
+    if (virNetServerAddSubServer(ctrl->server,
+                                 0, 0, 0, 1, 0, -1, 0, false,
+                                 virLXCControllerClientPrivateNew, NULL,
+                                 virLXCControllerClientPrivateFree, ctrl) < 0)
         goto error;

     if (virSecurityManagerSetSocketLabel(ctrl->securityManager, ctrl->def) < 0)
@@ -881,7 +881,7 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl)
     if (virSecurityManagerClearSocketLabel(ctrl->securityManager, ctrl->def) < 0)
         goto error;

-    if (virNetServerAddService(ctrl->server, svc, NULL) < 0)
+    if (virNetServerAddService(ctrl->server, 0, svc, NULL) < 0)
         goto error;
     virObjectUnref(svc);
     svc = NULL;
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index b642d6e..199b38f 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 #
-# Copyright (C) 2010-2014 Red Hat, Inc.
+# Copyright (C) 2010-2015 Red Hat, Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -403,7 +403,7 @@ elsif ($mode eq "server") {
         # First we print out a function declaration for the
         # real dispatcher body
         print "static int ${name}(\n";
-        print "    virNetServerPtr server,\n";
+        print "    virNetSubServerPtr subserver,\n";
         print "    virNetServerClientPtr client,\n";
         print "    virNetMessagePtr msg,\n";
         print "    virNetMessageErrorPtr rerr";
@@ -420,7 +420,7 @@ elsif ($mode eq "server") {
         # fixed function signature, for use in the dispatcher
         # table. This simply callers the real dispatcher method
         print "static int ${name}Helper(\n";
-        print "    virNetServerPtr server,\n";
+        print "    virNetSubServerPtr subserver,\n";
         print "    virNetServerClientPtr client,\n";
         print "    virNetMessagePtr msg,\n";
         print "    virNetMessageErrorPtr rerr,\n";
@@ -429,8 +429,9 @@ elsif ($mode eq "server") {
         print "{\n";
         print "  int rv;\n";
         print "  virThreadJobSet(\"$name\");\n";
-        print "  VIR_DEBUG(\"server=%p client=%p msg=%p rerr=%p args=%p ret=%p\", server, client, msg, rerr, args, ret);\n";
-        print "  rv = $name(server, client, msg, rerr";
+        print "  VIR_DEBUG(\"subserver=%p client=%p msg=%p rerr=%p args=%p ret=%p\", \n";
+        print "            subserver, client, msg, rerr, args, ret);\n";
+        print "  rv = $name(subserver, client, msg, rerr";
         if ($argtype ne "void") {
             print ", args";
         }
@@ -851,7 +852,7 @@ elsif ($mode eq "server") {

         # print functions signature
         print "static int $name(\n";
-        print "    virNetServerPtr server ATTRIBUTE_UNUSED,\n";
+        print "    virNetSubServerPtr subserver ATTRIBUTE_UNUSED,\n";
         print "    virNetServerClientPtr client,\n";
         print "    virNetMessagePtr msg ATTRIBUTE_UNUSED,\n";
         print "    virNetMessageErrorPtr rerr";
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index 47d83ba..83cd9fe 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -1,7 +1,7 @@
 /*
  * virnetserver.c: generic network RPC server
  *
- * Copyright (C) 2006-2012, 2014 Red Hat, Inc.
+ * Copyright (C) 2006-2015 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -58,20 +58,9 @@ struct _virNetServerSignal {
     void *opaque;
 };

-typedef struct _virNetServerJob virNetServerJob;
-typedef virNetServerJob *virNetServerJobPtr;
-
-struct _virNetServerJob {
-    virNetServerClientPtr client;
-    virNetMessagePtr msg;
-    virNetServerProgramPtr prog;
-};
-
 struct _virNetServer {
     virObjectLockable parent;

-    virThreadPoolPtr workers;
-
     bool privileged;

     size_t nsignals;
@@ -84,21 +73,9 @@ struct _virNetServer {
     virNetServerMDNSPtr mdns;
     virNetServerMDNSGroupPtr mdnsGroup;

-    size_t nservices;
-    virNetServerServicePtr *services;
-
-    size_t nprograms;
-    virNetServerProgramPtr *programs;
-
-    size_t nclients;                    /* Current clients count */
-    virNetServerClientPtr *clients;     /* Clients */
-    size_t nclients_max;                /* Max allowed clients count */
-    size_t nclients_unauth;             /* Unauthenticated clients count */
-    size_t nclients_unauth_max;         /* Max allowed unauth clients count */
-
-    int keepaliveInterval;
-    unsigned int keepaliveCount;
-    bool keepaliveRequired;
+    size_t nsubservers;
+    virNetSubServerPtr *subservers;
+    virJSONValuePtr subsrvObject;

     bool quit;

@@ -110,20 +87,11 @@ struct _virNetServer {
     size_t autoShutdownInhibitions;
     bool autoShutdownCallingInhibit;
     int autoShutdownInhibitFd;
-
-    virNetServerClientPrivNew clientPrivNew;
-    virNetServerClientPrivPreExecRestart clientPrivPreExecRestart;
-    virFreeCallback clientPrivFree;
-    void *clientPrivOpaque;
 };


 static virClassPtr virNetServerClass;
 static void virNetServerDispose(void *obj);
-static void virNetServerUpdateServicesLocked(virNetServerPtr srv,
-                                             bool enabled);
-static inline size_t virNetServerTrackPendingAuthLocked(virNetServerPtr srv);
-static inline size_t virNetServerTrackCompletedAuthLocked(virNetServerPtr srv);

 static int virNetServerOnceInit(void)
 {
@@ -139,221 +107,7 @@ static int virNetServerOnceInit(void)
 VIR_ONCE_GLOBAL_INIT(virNetServer)


-static int virNetServerProcessMsg(virNetServerPtr srv,
-                                  virNetServerClientPtr client,
-                                  virNetServerProgramPtr prog,
-                                  virNetMessagePtr msg)
-{
-    int ret = -1;
-    if (!prog) {
-        /* Only send back an error for type == CALL. Other
-         * message types are not expecting replies, so we
-         * must just log it & drop them
-         */
-        if (msg->header.type == VIR_NET_CALL ||
-            msg->header.type == VIR_NET_CALL_WITH_FDS) {
-            if (virNetServerProgramUnknownError(client,
-                                                msg,
-                                                &msg->header) < 0)
-                goto cleanup;
-        } else {
-            VIR_INFO("Dropping client mesage, unknown program %d version %d type %d proc %d",
-                     msg->header.prog, msg->header.vers,
-                     msg->header.type, msg->header.proc);
-            /* Send a dummy reply to free up 'msg' & unblock client rx */
-            virNetMessageClear(msg);
-            msg->header.type = VIR_NET_REPLY;
-            if (virNetServerClientSendMessage(client, msg) < 0)
-                goto cleanup;
-        }
-        goto done;
-    }
-
-    if (virNetServerProgramDispatch(prog,
-                                    srv,
-                                    client,
-                                    msg) < 0)
-        goto cleanup;
-
- done:
-    ret = 0;
-
- cleanup:
-    return ret;
-}
-
-static void virNetServerHandleJob(void *jobOpaque, void *opaque)
-{
-    virNetServerPtr srv = opaque;
-    virNetServerJobPtr job = jobOpaque;
-
-    VIR_DEBUG("server=%p client=%p message=%p prog=%p",
-              srv, job->client, job->msg, job->prog);
-
-    if (virNetServerProcessMsg(srv, job->client, job->prog, job->msg) < 0)
-        goto error;
-
-    virObjectUnref(job->prog);
-    virObjectUnref(job->client);
-    VIR_FREE(job);
-    return;
-
- error:
-    virObjectUnref(job->prog);
-    virNetMessageFree(job->msg);
-    virNetServerClientClose(job->client);
-    virObjectUnref(job->client);
-    VIR_FREE(job);
-}
-
-static int virNetServerDispatchNewMessage(virNetServerClientPtr client,
-                                          virNetMessagePtr msg,
-                                          void *opaque)
-{
-    virNetServerPtr srv = opaque;
-    virNetServerProgramPtr prog = NULL;
-    unsigned int priority = 0;
-    size_t i;
-    int ret = -1;
-
-    VIR_DEBUG("server=%p client=%p message=%p",
-              srv, client, msg);
-
-    virObjectLock(srv);
-    for (i = 0; i < srv->nprograms; i++) {
-        if (virNetServerProgramMatches(srv->programs[i], msg)) {
-            prog = srv->programs[i];
-            break;
-        }
-    }
-
-    if (srv->workers) {
-        virNetServerJobPtr job;
-
-        if (VIR_ALLOC(job) < 0)
-            goto cleanup;
-
-        job->client = client;
-        job->msg = msg;
-
-        if (prog) {
-            virObjectRef(prog);
-            job->prog = prog;
-            priority = virNetServerProgramGetPriority(prog, msg->header.proc);
-        }
-
-        ret = virThreadPoolSendJob(srv->workers, priority, job);
-
-        if (ret < 0) {
-            VIR_FREE(job);
-            virObjectUnref(prog);
-        }
-    } else {
-        ret = virNetServerProcessMsg(srv, client, prog, msg);
-    }
-
- cleanup:
-    virObjectUnlock(srv);
-
-    return ret;
-}
-
-
-static int virNetServerAddClient(virNetServerPtr srv,
-                                 virNetServerClientPtr client)
-{
-    virObjectLock(srv);
-
-    if (srv->nclients >= srv->nclients_max) {
-        virReportError(VIR_ERR_RPC,
-                       _("Too many active clients (%zu), dropping connection from %s"),
-                       srv->nclients_max, virNetServerClientRemoteAddrString(client));
-        goto error;
-    }
-
-    if (virNetServerClientInit(client) < 0)
-        goto error;
-
-    if (VIR_EXPAND_N(srv->clients, srv->nclients, 1) < 0)
-        goto error;
-    srv->clients[srv->nclients-1] = client;
-    virObjectRef(client);
-
-    if (virNetServerClientNeedAuth(client))
-        virNetServerTrackPendingAuthLocked(srv);
-
-    if (srv->nclients_unauth_max &&
-        srv->nclients_unauth == srv->nclients_unauth_max) {
-        /* Temporarily stop accepting new clients */
-        VIR_INFO("Temporarily suspending services "
-                 "due to max_anonymous_clients");
-        virNetServerUpdateServicesLocked(srv, false);
-    }
-
-    if (srv->nclients == srv->nclients_max) {
-        /* Temporarily stop accepting new clients */
-        VIR_INFO("Temporarily suspending services due to max_clients");
-        virNetServerUpdateServicesLocked(srv, false);
-    }
-
-    virNetServerClientSetDispatcher(client,
-                                    virNetServerDispatchNewMessage,
-                                    srv);
-
-    virNetServerClientInitKeepAlive(client, srv->keepaliveInterval,
-                                    srv->keepaliveCount);
-
-    virObjectUnlock(srv);
-    return 0;
-
- error:
-    virObjectUnlock(srv);
-    return -1;
-}
-
-static int virNetServerDispatchNewClient(virNetServerServicePtr svc,
-                                         virNetSocketPtr clientsock,
-                                         void *opaque)
-{
-    virNetServerPtr srv = opaque;
-    virNetServerClientPtr client;
-
-    if (!(client = virNetServerClientNew(clientsock,
-                                         virNetServerServiceGetAuth(svc),
-                                         virNetServerServiceIsReadonly(svc),
-                                         virNetServerServiceGetMaxRequests(svc),
-#if WITH_GNUTLS
-                                         virNetServerServiceGetTLSContext(svc),
-#endif
-                                         srv->clientPrivNew,
-                                         srv->clientPrivPreExecRestart,
-                                         srv->clientPrivFree,
-                                         srv->clientPrivOpaque)))
-        return -1;
-
-    if (virNetServerAddClient(srv, client) < 0) {
-        virNetServerClientClose(client);
-        virObjectUnref(client);
-        return -1;
-    }
-    virObjectUnref(client);
-    return 0;
-}
-
-
-virNetServerPtr virNetServerNew(size_t min_workers,
-                                size_t max_workers,
-                                size_t priority_workers,
-                                size_t max_clients,
-                                size_t max_anonymous_clients,
-                                int keepaliveInterval,
-                                unsigned int keepaliveCount,
-                                bool keepaliveRequired,
-                                const char *mdnsGroupName,
-                                virNetServerClientPrivNew clientPrivNew,
-                                virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
-                                virFreeCallback clientPrivFree,
-                                void *clientPrivOpaque)
+virNetServerPtr virNetServerNew(const char *mdnsGroupName)
 {
     virNetServerPtr srv;
     struct sigaction sig_action;
@@ -364,23 +118,7 @@ virNetServerPtr virNetServerNew(size_t min_workers,
     if (!(srv = virObjectLockableNew(virNetServerClass)))
         return NULL;

-    if (max_workers &&
-        !(srv->workers = virThreadPoolNew(min_workers, max_workers,
-                                          priority_workers,
-                                          virNetServerHandleJob,
-                                          srv)))
-        goto error;
-
-    srv->nclients_max = max_clients;
-    srv->nclients_unauth_max = max_anonymous_clients;
-    srv->keepaliveInterval = keepaliveInterval;
-    srv->keepaliveCount = keepaliveCount;
-    srv->keepaliveRequired = keepaliveRequired;
     srv->sigwrite = srv->sigread = -1;
-    srv->clientPrivNew = clientPrivNew;
-    srv->clientPrivPreExecRestart = clientPrivPreExecRestart;
-    srv->clientPrivFree = clientPrivFree;
-    srv->clientPrivOpaque = clientPrivOpaque;
     srv->privileged = geteuid() == 0;
     srv->autoShutdownInhibitFd = -1;

@@ -409,101 +147,198 @@ virNetServerPtr virNetServerNew(size_t min_workers,
 }


-virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object,
-                                               virNetServerClientPrivNew clientPrivNew,
-                                               virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart,
-                                               virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
-                                               virFreeCallback clientPrivFree,
-                                               void *clientPrivOpaque)
+int
+virNetServerAddSubServer(virNetServerPtr srv,
+                         size_t min_workers,
+                         size_t max_workers,
+                         size_t priority_workers,
+                         size_t max_clients,
+                         size_t max_anonymous_clients,
+                         int keepaliveInterval,
+                         unsigned int keepaliveCount,
+                         bool keepaliveRequired,
+                         virNetServerClientPrivNew clientPrivNew,
+                         virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
+                         virFreeCallback clientPrivFree,
+                         void *clientPrivOpaque)
 {
-    virNetServerPtr srv = NULL;
-    virJSONValuePtr clients;
-    virJSONValuePtr services;
-    size_t i;
+    int ret = -1;
+    virNetSubServerPtr subsrv = NULL;
+
+    virObjectLock(srv);
+
+    subsrv = virNetSubServerNew(min_workers, max_workers, priority_workers,
+                                max_clients, max_anonymous_clients,
+                                keepaliveInterval, keepaliveCount,
+                                keepaliveRequired, clientPrivNew,
+                                clientPrivPreExecRestart, clientPrivFree,
+                                clientPrivOpaque);
+
+    if (!subsrv ||
+        VIR_APPEND_ELEMENT(srv->subservers, srv->nsubservers, subsrv) < 0)
+        goto cleanup;
+
+    ret = srv->nsubservers - 1;
+    subsrv = NULL;
+ cleanup:
+    virObjectUnlock(srv);
+    VIR_FREE(subsrv);
+    return ret;
+}
+
+
+/*
+ * Separate function merely for the purpose of unified error
+ * reporting.
+ */
+static virNetSubServerPtr
+virNetServerGetSubServerInternal(virNetServerPtr srv,
+                                 int subServerID)
+{
+    if (subServerID < 0 || subServerID >= srv->nsubservers) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("Invalid subserver ID: %d"),
+                       subServerID);
+        return NULL;
+    }
+
+    return virObjectRef(srv->subservers[subServerID]);
+}
+
+/*
+ * The subserver is locked after this function.
+ */
+virNetSubServerPtr
+virNetServerGetSubServer(virNetServerPtr srv,
+                         int subServerID)
+{
+    virNetSubServerPtr subsrv = NULL;
+
+    virObjectLock(srv);
+    subsrv = virNetServerGetSubServerInternal(srv, subServerID);
+    virObjectUnlock(srv);
+
+    return subsrv;
+}
+
+int
+virNetServerAddSubServerPostExec(virNetServerPtr srv,
+                                 virNetServerClientPrivNew clientPrivNew,
+                                 virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart,
+                                 virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
+                                 virFreeCallback clientPrivFree,
+                                 void *clientPrivOpaque)
+{
+    bool keepaliveRequired;
     int n;
-    unsigned int min_workers;
+    int ret = -1;
+    int subServerID;
+    size_t i;
+    unsigned int keepaliveCount;
+    unsigned int keepaliveInterval;
+    unsigned int max_anonymous_clients;
+    unsigned int max_clients;
     unsigned int max_workers;
+    unsigned int min_workers;
     unsigned int priority_workers;
-    unsigned int max_clients;
-    unsigned int max_anonymous_clients;
-    unsigned int keepaliveInterval;
-    unsigned int keepaliveCount;
-    bool keepaliveRequired;
-    const char *mdnsGroupName = NULL;
+    virJSONValuePtr clients;
+    virJSONValuePtr object;
+    virJSONValuePtr services;
+
+    virObjectLock(srv);
+
+    if (!srv->subsrvObject) {
+        /*
+         * For back-compat we return -2 when there are no more saved
+         * subserver data so any new subservers can be added without
+         * restoring as well as without any error.
+         */
+        return -2;
+    }
+
+    if (virJSONValueIsArray(srv->subsrvObject)) {
+        object = virJSONValueArraySteal(srv->subsrvObject, 0);
+        if (virJSONValueArraySize(srv->subsrvObject) == 0) {
+            virJSONValueFree(srv->subsrvObject);
+            srv->subsrvObject = NULL;
+        }
+    } else {
+        object = srv->subsrvObject;
+        srv->subsrvObject = NULL;
+    }

     if (virJSONValueObjectGetNumberUint(object, "min_workers", &min_workers) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing min_workers data in JSON document"));
-        goto error;
+        goto cleanup;
     }
     if (virJSONValueObjectGetNumberUint(object, "max_workers", &max_workers) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing max_workers data in JSON document"));
-        goto error;
+        goto cleanup;
     }
     if (virJSONValueObjectGetNumberUint(object, "priority_workers", &priority_workers) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing priority_workers data in JSON document"));
-        goto error;
+        goto cleanup;
     }
     if (virJSONValueObjectGetNumberUint(object, "max_clients", &max_clients) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Missing max_clients data in JSON document"));
-        goto error;
-    }
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("Missing max_clients data in JSON document"));
+                goto cleanup;
+            }
     if (virJSONValueObjectHasKey(object, "max_anonymous_clients")) {
         if (virJSONValueObjectGetNumberUint(object, "max_anonymous_clients",
                                             &max_anonymous_clients) < 0) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("Malformed max_anonymous_clients data in JSON document"));
-            goto error;
+            goto cleanup;
         }
     } else {
         max_anonymous_clients = max_clients;
     }
-    if (virJSONValueObjectGetNumberUint(object, "keepaliveInterval", &keepaliveInterval) < 0) {
+
+    if (virJSONValueObjectGetNumberUint(object, "keepaliveInterval",
+                                        &keepaliveInterval) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing keepaliveInterval data in JSON document"));
-        goto error;
+        goto cleanup;
     }
     if (virJSONValueObjectGetNumberUint(object, "keepaliveCount", &keepaliveCount) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing keepaliveCount data in JSON document"));
-        goto error;
+        goto cleanup;
     }
     if (virJSONValueObjectGetBoolean(object, "keepaliveRequired", &keepaliveRequired) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing keepaliveRequired data in JSON document"));
-        goto error;
-    }
-
-    if (virJSONValueObjectHasKey(object, "mdnsGroupName") &&
-        (!(mdnsGroupName = virJSONValueObjectGetString(object, "mdnsGroupName")))) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Malformed mdnsGroupName data in JSON document"));
-        goto error;
+        goto cleanup;
     }

-    if (!(srv = virNetServerNew(min_workers, max_clients,
-                                priority_workers, max_clients,
-                                max_anonymous_clients,
-                                keepaliveInterval, keepaliveCount,
-                                keepaliveRequired, mdnsGroupName,
-                                clientPrivNew, clientPrivPreExecRestart,
-                                clientPrivFree, clientPrivOpaque)))
-        goto error;
+    if ((subServerID = virNetServerAddSubServer(srv,
+                                                min_workers, max_clients,
+                                                priority_workers, max_clients,
+                                                max_anonymous_clients,
+                                                keepaliveInterval,
+                                                keepaliveCount,
+                                                keepaliveRequired,
+                                                clientPrivNew,
+                                                clientPrivPreExecRestart,
+                                                clientPrivFree,
+                                                clientPrivOpaque)) < 0)
+        goto cleanup;

     if (!(services = virJSONValueObjectGet(object, "services"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing services data in JSON document"));
-        goto error;
+        goto cleanup;
     }

-    n =  virJSONValueArraySize(services);
+    n = virJSONValueArraySize(services);
     if (n < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Malformed services data in JSON document"));
-        goto error;
+        goto cleanup;
     }

     for (i = 0; i < n; i++) {
@@ -512,31 +347,31 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object,
         if (!child) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("Missing service data in JSON document"));
-            goto error;
+            goto cleanup;
         }

         if (!(service = virNetServerServiceNewPostExecRestart(child)))
-            goto error;
+            goto cleanup;

         /* XXX mdns entry names ? */
-        if (virNetServerAddService(srv, service, NULL) < 0) {
+        if (virNetServerAddService(srv, subServerID,
+                                   service, NULL) < 0) {
             virObjectUnref(service);
-            goto error;
+            goto cleanup;
         }
     }

-
     if (!(clients = virJSONValueObjectGet(object, "clients"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing clients data in JSON document"));
-        goto error;
+        goto cleanup;
     }

-    n =  virJSONValueArraySize(clients);
+    n = virJSONValueArraySize(clients);
     if (n < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Malformed clients data in JSON document"));
-        goto error;
+        goto cleanup;
     }

     for (i = 0; i < n; i++) {
@@ -545,7 +380,7 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object,
         if (!child) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("Missing client data in JSON document"));
-            goto error;
+            goto cleanup;
         }

         if (!(client = virNetServerClientNewPostExecRestart(child,
@@ -553,17 +388,58 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object,
                                                             clientPrivPreExecRestart,
                                                             clientPrivFree,
                                                             clientPrivOpaque)))
-            goto error;
+            goto cleanup;

-        if (virNetServerAddClient(srv, client) < 0) {
+        if (virNetSubServerAddClient(srv->subservers[subServerID],
+                                     client) < 0) {
             virObjectUnref(client);
-            goto error;
+            goto cleanup;
         }
         virObjectUnref(client);
     }

-    return srv;
+    ret = subServerID;
+ cleanup:
+    virJSONValueFree(object);
+    virObjectUnlock(srv);
+    return ret;
+}
+
+
+virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object)
+{
+    const char *mdnsGroupName = NULL;
+    virNetServerPtr srv = NULL;
+
+    if (virJSONValueObjectHasKey(object, "mdnsGroupName") &&
+        (!(mdnsGroupName = virJSONValueObjectGetString(object, "mdnsGroupName")))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Malformed mdnsGroupName data in JSON document"));
+        goto error;
+    }

+    if (!(srv = virNetServerNew(mdnsGroupName)))
+        goto error;
+
+    if (!virJSONValueObjectHasKey(object, "subservers")) {
+        /*
+         * Old format, we have to do this for back-compat.
+         */
+        srv->subsrvObject = virJSONValueCopy(object);
+    } else {
+        virJSONValuePtr subservers = virJSONValueObjectGet(object, "subservers");
+
+        if (!subservers) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Malformed subservers data in JSON document"));
+            goto error;
+        }
+        srv->subsrvObject = virJSONValueCopy(subservers);
+    }
+    if (!srv->subsrvObject)
+        goto error;
+
+    return srv;
  error:
     virObjectUnref(srv);
     return NULL;
@@ -572,9 +448,7 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object,

 virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv)
 {
-    virJSONValuePtr object;
-    virJSONValuePtr clients;
-    virJSONValuePtr services;
+    virJSONValuePtr object, srvArray = NULL;
     size_t i;

     virObjectLock(srv);
@@ -582,51 +456,6 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv)
     if (!(object = virJSONValueNewObject()))
         goto error;

-    if (virJSONValueObjectAppendNumberUint(object, "min_workers",
-                                           virThreadPoolGetMinWorkers(srv->workers)) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set min_workers data in JSON document"));
-        goto error;
-    }
-    if (virJSONValueObjectAppendNumberUint(object, "max_workers",
-                                           virThreadPoolGetMaxWorkers(srv->workers)) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set max_workers data in JSON document"));
-        goto error;
-    }
-    if (virJSONValueObjectAppendNumberUint(object, "priority_workers",
-                                           virThreadPoolGetPriorityWorkers(srv->workers)) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set priority_workers data in JSON document"));
-        goto error;
-    }
-    if (virJSONValueObjectAppendNumberUint(object, "max_clients", srv->nclients_max) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set max_clients data in JSON document"));
-        goto error;
-    }
-    if (virJSONValueObjectAppendNumberUint(object, "max_anonymous_clients",
-                                           srv->nclients_unauth_max) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set max_anonymous_clients data in JSON document"));
-        goto error;
-    }
-    if (virJSONValueObjectAppendNumberUint(object, "keepaliveInterval", srv->keepaliveInterval) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set keepaliveInterval data in JSON document"));
-        goto error;
-    }
-    if (virJSONValueObjectAppendNumberUint(object, "keepaliveCount", srv->keepaliveCount) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set keepaliveCount data in JSON document"));
-        goto error;
-    }
-    if (virJSONValueObjectAppendBoolean(object, "keepaliveRequired", srv->keepaliveRequired) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Cannot set keepaliveRequired data in JSON document"));
-        goto error;
-    }
-
     if (srv->mdnsGroupName &&
         virJSONValueObjectAppendString(object, "mdnsGroupName", srv->mdnsGroupName) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -634,36 +463,18 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv)
         goto error;
     }

-    services = virJSONValueNewArray();
-    if (virJSONValueObjectAppend(object, "services", services) < 0) {
-        virJSONValueFree(services);
+    if (!(srvArray = virJSONValueNewArray()))
         goto error;
-    }
-
-    for (i = 0; i < srv->nservices; i++) {
-        virJSONValuePtr child;
-        if (!(child = virNetServerServicePreExecRestart(srv->services[i])))
-            goto error;
-
-        if (virJSONValueArrayAppend(services, child) < 0) {
-            virJSONValueFree(child);
-            goto error;
-        }
-    }

-    clients = virJSONValueNewArray();
-    if (virJSONValueObjectAppend(object, "clients", clients) < 0) {
-        virJSONValueFree(clients);
-        goto error;
-    }
+    for (i = 0; i < srv->nsubservers; i++) {
+        virJSONValuePtr subsrvJSON = NULL;
+        subsrvJSON = virNetSubServerPreExecRestart(srv->subservers[i]);

-    for (i = 0; i < srv->nclients; i++) {
-        virJSONValuePtr child;
-        if (!(child = virNetServerClientPreExecRestart(srv->clients[i])))
+        if (!subsrvJSON)
             goto error;

-        if (virJSONValueArrayAppend(clients, child) < 0) {
-            virJSONValueFree(child);
+        if (virJSONValueArrayAppend(srvArray, subsrvJSON) < 0) {
+            virJSONValueFree(subsrvJSON);
             goto error;
         }
     }
@@ -674,6 +485,7 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv)

  error:
     virJSONValueFree(object);
+    virJSONValueFree(srvArray);
     virObjectUnlock(srv);
     return NULL;
 }
@@ -959,56 +771,68 @@ int virNetServerAddSignalHandler(virNetServerPtr srv,
 }


-
-int virNetServerAddService(virNetServerPtr srv,
-                           virNetServerServicePtr svc,
-                           const char *mdnsEntryName)
+static inline int
+virNetServerAddMDNSEntry(virNetServerPtr srv,
+                         const char *mdnsEntryName,
+                         int port)
 {
+    int ret = -1;
+
     virObjectLock(srv);

-    if (VIR_EXPAND_N(srv->services, srv->nservices, 1) < 0)
-        goto error;
+    if (srv && mdnsEntryName &&
+        !virNetServerMDNSAddEntry(srv->mdnsGroup, mdnsEntryName, port))
+        goto cleanup;

-    if (mdnsEntryName) {
-        int port = virNetServerServiceGetPort(svc);
+    ret = 0;
+ cleanup:
+    virObjectUnlock(srv);
+    return ret;
+}

-        if (!virNetServerMDNSAddEntry(srv->mdnsGroup,
-                                      mdnsEntryName,
-                                      port))
-            goto error;
-    }
+int virNetServerAddService(virNetServerPtr srv,
+                           int subServerID,
+                           virNetServerServicePtr svc,
+                           const char *mdnsEntryName)
+{
+    int ret = -1;
+    virNetSubServerPtr subsrv = NULL;

-    srv->services[srv->nservices-1] = svc;
-    virObjectRef(svc);
+    subsrv = virNetServerGetSubServerInternal(srv, subServerID);
+    if (!subsrv)
+        goto cleanup;

-    virNetServerServiceSetDispatcher(svc,
-                                     virNetServerDispatchNewClient,
-                                     srv);
+    if (virNetSubServerAddService(subsrv, svc) < 0)
+        goto cleanup;

-    virObjectUnlock(srv);
-    return 0;
+    if (virNetServerAddMDNSEntry(srv, mdnsEntryName,
+                                 virNetServerServiceGetPort(svc)) < 0)
+        goto cleanup;

- error:
-    virObjectUnlock(srv);
-    return -1;
+    ret = 0;
+ cleanup:
+    virObjectUnref(subsrv);
+    return ret;
 }

 int virNetServerAddProgram(virNetServerPtr srv,
+                           int subServerID,
                            virNetServerProgramPtr prog)
 {
-    virObjectLock(srv);
-
-    if (VIR_EXPAND_N(srv->programs, srv->nprograms, 1) < 0)
-        goto error;
+    int ret = -1;
+    virNetSubServerPtr subsrv = NULL;

-    srv->programs[srv->nprograms-1] = virObjectRef(prog);
+    subsrv = virNetServerGetSubServer(srv, subServerID);
+    if (!subsrv)
+        goto cleanup;

-    virObjectUnlock(srv);
-    return 0;
+    if (virNetSubServerAddProgram(subsrv, prog) < 0)
+        goto cleanup;

- error:
-    virObjectUnlock(srv);
-    return -1;
+    ret = 0;
+ cleanup:
+    virObjectUnref(subsrv);
+    return ret;
 }

 #if WITH_GNUTLS
@@ -1036,55 +860,17 @@ static void virNetServerAutoShutdownTimer(int timerid ATTRIBUTE_UNUSED,
     virObjectUnlock(srv);
 }

-
-static void
-virNetServerUpdateServicesLocked(virNetServerPtr srv,
-                                 bool enabled)
-{
-    size_t i;
-
-    for (i = 0; i < srv->nservices; i++)
-        virNetServerServiceToggle(srv->services[i], enabled);
-}
-
-
 void virNetServerUpdateServices(virNetServerPtr srv,
                                 bool enabled)
 {
+    size_t i;
+
     virObjectLock(srv);
-    virNetServerUpdateServicesLocked(srv, enabled);
+    for (i = 0; i < srv->nsubservers; i++)
+        virNetSubServerUpdateServices(srv->subservers[i], enabled);
     virObjectUnlock(srv);
 }

-/**
- * virNetServerCheckLimits:
- * @srv: server to check limits on
- *
- * Check if limits like max_clients or max_anonymous_clients
- * are satisfied and if so, re-enable accepting new clients.
- * The @srv must be locked when this function is called.
- */
-static void
-virNetServerCheckLimits(virNetServerPtr srv)
-{
-    /* Enable services if we can accept a new client.
-     * The new client can be accepted if both max_clients and
-     * max_anonymous_clients wouldn't get overcommitted by
-     * accepting it. */
-    VIR_DEBUG("Considering re-enabling services: "
-              "nclients=%zu nclients_max=%zu "
-              "nclients_unauth=%zu nclients_unauth_max=%zu",
-              srv->nclients, srv->nclients_max,
-              srv->nclients_unauth, srv->nclients_unauth_max);
-    if (srv->nclients < srv->nclients_max &&
-        (!srv->nclients_unauth_max ||
-         srv->nclients_unauth < srv->nclients_unauth_max)) {
-        /* Now it makes sense to accept() a new client. */
-        VIR_INFO("Re-enabling services");
-        virNetServerUpdateServicesLocked(srv, true);
-    }
-}
-
 void virNetServerRun(virNetServerPtr srv)
 {
     int timerid = -1;
@@ -1093,6 +879,12 @@ void virNetServerRun(virNetServerPtr srv)

     virObjectLock(srv);

+    if (srv->subsrvObject) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Not all subservers restored, cannot run server"));
+        goto cleanup;
+    }
+
     if (srv->mdns &&
         virNetServerMDNSStart(srv->mdns) < 0)
         goto cleanup;
@@ -1120,17 +912,23 @@ void virNetServerRun(virNetServerPtr srv)
          */
         if (srv->autoShutdownTimeout) {
             if (timerActive) {
-                if (srv->clients) {
-                    VIR_DEBUG("Deactivating shutdown timer %d", timerid);
-                    virEventUpdateTimeout(timerid, -1);
-                    timerActive = false;
+                for (i = 0; i < srv->nsubservers; i++) {
+                    if (virNetSubServerHasClients(srv->subservers[i])) {
+                        VIR_DEBUG("Deactivating shutdown timer %d", timerid);
+                        virEventUpdateTimeout(timerid, -1);
+                        timerActive = false;
+                        break;
+                    }
                 }
             } else {
-                if (!srv->clients) {
-                    VIR_DEBUG("Activating shutdown timer %d", timerid);
-                    virEventUpdateTimeout(timerid,
-                                          srv->autoShutdownTimeout * 1000);
-                    timerActive = true;
+                for (i = 0; i < srv->nsubservers; i++) {
+                    if (!virNetSubServerHasClients(srv->subservers[i])) {
+                        VIR_DEBUG("Activating shutdown timer %d", timerid);
+                        virEventUpdateTimeout(timerid,
+                                              srv->autoShutdownTimeout * 1000);
+                        timerActive = true;
+                        break;
+                    }
                 }
             }
         }
@@ -1143,30 +941,8 @@ void virNetServerRun(virNetServerPtr srv)
         }
         virObjectLock(srv);

-    reprocess:
-        for (i = 0; i < srv->nclients; i++) {
-            /* Coverity 5.3.0 couldn't see that srv->clients is non-NULL
-             * if srv->nclients is non-zero.  */
-            sa_assert(srv->clients);
-            if (virNetServerClientWantClose(srv->clients[i]))
-                virNetServerClientClose(srv->clients[i]);
-            if (virNetServerClientIsClosed(srv->clients[i])) {
-                virNetServerClientPtr client = srv->clients[i];
-
-                VIR_DELETE_ELEMENT(srv->clients, i, srv->nclients);
-
-                if (virNetServerClientNeedAuth(client))
-                    virNetServerTrackCompletedAuthLocked(srv);
-
-                virNetServerCheckLimits(srv);
-
-                virObjectUnlock(srv);
-                virObjectUnref(client);
-                virObjectLock(srv);
-
-                goto reprocess;
-            }
-        }
+        for (i = 0; i < srv->nsubservers; i++)
+            virNetSubServerProcessClients(srv->subservers[i]);
     }

  cleanup:
@@ -1191,11 +967,6 @@ void virNetServerDispose(void *obj)

     VIR_FORCE_CLOSE(srv->autoShutdownInhibitFd);

-    for (i = 0; i < srv->nservices; i++)
-        virNetServerServiceToggle(srv->services[i], false);
-
-    virThreadPoolFree(srv->workers);
-
     for (i = 0; i < srv->nsignals; i++) {
         sigaction(srv->signals[i]->signum, &srv->signals[i]->oldaction, NULL);
         VIR_FREE(srv->signals[i]);
@@ -1206,22 +977,14 @@ void virNetServerDispose(void *obj)
     if (srv->sigwatch > 0)
         virEventRemoveHandle(srv->sigwatch);

-    for (i = 0; i < srv->nservices; i++)
-        virObjectUnref(srv->services[i]);
-    VIR_FREE(srv->services);
-
-    for (i = 0; i < srv->nprograms; i++)
-        virObjectUnref(srv->programs[i]);
-    VIR_FREE(srv->programs);
-
-    for (i = 0; i < srv->nclients; i++) {
-        virNetServerClientClose(srv->clients[i]);
-        virObjectUnref(srv->clients[i]);
-    }
-    VIR_FREE(srv->clients);
+    for (i = 0; i < srv->nsubservers; i++)
+        virObjectUnref(srv->subservers[i]);
+    VIR_FREE(srv->subservers);

     VIR_FREE(srv->mdnsGroupName);
     virNetServerMDNSFree(srv->mdns);
+
+    virJSONValueFree(srv->subsrvObject);
 }

 void virNetServerClose(virNetServerPtr srv)
@@ -1233,48 +996,8 @@ void virNetServerClose(virNetServerPtr srv)

     virObjectLock(srv);

-    for (i = 0; i < srv->nservices; i++)
-        virNetServerServiceClose(srv->services[i]);
-
-    virObjectUnlock(srv);
-}
-
-bool virNetServerKeepAliveRequired(virNetServerPtr srv)
-{
-    bool required;
-    virObjectLock(srv);
-    required = srv->keepaliveRequired;
-    virObjectUnlock(srv);
-    return required;
-}
-
-static inline size_t
-virNetServerTrackPendingAuthLocked(virNetServerPtr srv)
-{
-    return ++srv->nclients_unauth;
-}
-
-static inline size_t
-virNetServerTrackCompletedAuthLocked(virNetServerPtr srv)
-{
-    return --srv->nclients_unauth;
-}
-
-size_t virNetServerTrackPendingAuth(virNetServerPtr srv)
-{
-    size_t ret;
-    virObjectLock(srv);
-    ret = virNetServerTrackPendingAuthLocked(srv);
-    virObjectUnlock(srv);
-    return ret;
-}
+    for (i = 0; i < srv->nsubservers; i++)
+        virNetSubServerClose(srv->subservers[i]);

-size_t virNetServerTrackCompletedAuth(virNetServerPtr srv)
-{
-    size_t ret;
-    virObjectLock(srv);
-    ret = virNetServerTrackCompletedAuthLocked(srv);
-    virNetServerCheckLimits(srv);
     virObjectUnlock(srv);
-    return ret;
 }
diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h
index 8c5ae07..6b1630b 100644
--- a/src/rpc/virnetserver.h
+++ b/src/rpc/virnetserver.h
@@ -1,7 +1,7 @@
 /*
  * virnetserver.h: generic network RPC server
  *
- * Copyright (C) 2006-2011 Red Hat, Inc.
+ * Copyright (C) 2006-2015 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -29,32 +29,37 @@
 # ifdef WITH_GNUTLS
 #  include "virnettlscontext.h"
 # endif
+# include "virobject.h"
+# include "virjson.h"
 # include "virnetserverprogram.h"
 # include "virnetserverclient.h"
 # include "virnetserverservice.h"
-# include "virobject.h"
-# include "virjson.h"
-
-virNetServerPtr virNetServerNew(size_t min_workers,
-                                size_t max_workers,
-                                size_t priority_workers,
-                                size_t max_clients,
-                                size_t max_anonymous_clients,
-                                int keepaliveInterval,
-                                unsigned int keepaliveCount,
-                                bool keepaliveRequired,
-                                const char *mdnsGroupName,
-                                virNetServerClientPrivNew clientPrivNew,
-                                virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
-                                virFreeCallback clientPrivFree,
-                                void *clientPrivOpaque);
-
-virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object,
-                                               virNetServerClientPrivNew clientPrivNew,
-                                               virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart,
-                                               virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
-                                               virFreeCallback clientPrivFree,
-                                               void *clientPrivOpaque);
+# include "virnetsubserver.h"
+
+virNetServerPtr virNetServerNew(const char *mdnsGroupName);
+
+int virNetServerAddSubServer(virNetServerPtr srv,
+                             size_t min_workers,
+                             size_t max_workers,
+                             size_t priority_workers,
+                             size_t max_clients,
+                             size_t max_anonymous_clients,
+                             int keepaliveInterval,
+                             unsigned int keepaliveCount,
+                             bool keepaliveRequired,
+                             virNetServerClientPrivNew clientPrivNew,
+                             virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
+                             virFreeCallback clientPrivFree,
+                             void *clientPrivOpaque);
+
+int virNetServerAddSubServerPostExec(virNetServerPtr srv,
+                                     virNetServerClientPrivNew clientPrivNew,
+                                     virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart,
+                                     virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
+                                     virFreeCallback clientPrivFree,
+                                     void *clientPrivOpaque);
+
+virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object);

 virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv);

@@ -76,10 +81,12 @@ int virNetServerAddSignalHandler(virNetServerPtr srv,
                                  void *opaque);

 int virNetServerAddService(virNetServerPtr srv,
+                           int subServerID,
                            virNetServerServicePtr svc,
                            const char *mdnsEntryName);

 int virNetServerAddProgram(virNetServerPtr srv,
+                           int subServerID,
                            virNetServerProgramPtr prog);

 # if WITH_GNUTLS
@@ -96,9 +103,7 @@ void virNetServerQuit(virNetServerPtr srv);

 void virNetServerClose(virNetServerPtr srv);

-bool virNetServerKeepAliveRequired(virNetServerPtr srv);
-
-size_t virNetServerTrackPendingAuth(virNetServerPtr srv);
-size_t virNetServerTrackCompletedAuth(virNetServerPtr srv);
+virNetSubServerPtr virNetServerGetSubServer(virNetServerPtr srv,
+                                            int subServerID);

 #endif
diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c
index a4d9295..c043870 100644
--- a/src/rpc/virnetserverprogram.c
+++ b/src/rpc/virnetserverprogram.c
@@ -1,7 +1,7 @@
 /*
  * virnetserverprogram.c: generic network RPC server program
  *
- * Copyright (C) 2006-2012 Red Hat, Inc.
+ * Copyright (C) 2006-2015 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -253,7 +253,7 @@ int virNetServerProgramUnknownError(virNetServerClientPtr client,

 static int
 virNetServerProgramDispatchCall(virNetServerProgramPtr prog,
-                                virNetServerPtr server,
+                                virNetSubServerPtr subserver,
                                 virNetServerClientPtr client,
                                 virNetMessagePtr msg);

@@ -273,7 +273,7 @@ virNetServerProgramDispatchCall(virNetServerProgramPtr prog,
  * Returns 0 if the message was dispatched, -1 upon fatal error
  */
 int virNetServerProgramDispatch(virNetServerProgramPtr prog,
-                                virNetServerPtr server,
+                                virNetSubServerPtr subserver,
                                 virNetServerClientPtr client,
                                 virNetMessagePtr msg)
 {
@@ -304,7 +304,7 @@ int virNetServerProgramDispatch(virNetServerProgramPtr prog,
     switch (msg->header.type) {
     case VIR_NET_CALL:
     case VIR_NET_CALL_WITH_FDS:
-        ret = virNetServerProgramDispatchCall(prog, server, client, msg);
+        ret = virNetServerProgramDispatchCall(prog, subserver, client, msg);
         break;

     case VIR_NET_STREAM:
@@ -367,7 +367,7 @@ int virNetServerProgramDispatch(virNetServerProgramPtr prog,
  */
 static int
 virNetServerProgramDispatchCall(virNetServerProgramPtr prog,
-                                virNetServerPtr server,
+                                virNetSubServerPtr subserver,
                                 virNetServerClientPtr client,
                                 virNetMessagePtr msg)
 {
@@ -434,7 +434,7 @@ virNetServerProgramDispatchCall(virNetServerProgramPtr prog,
      *
      *   'args and 'ret'
      */
-    rv = (dispatcher->func)(server, client, msg, &rerr, arg, ret);
+    rv = (dispatcher->func)(subserver, client, msg, &rerr, arg, ret);

     if (virIdentitySetCurrent(NULL) < 0)
         goto error;
diff --git a/src/rpc/virnetserverprogram.h b/src/rpc/virnetserverprogram.h
index c1ae17e..f292bc7 100644
--- a/src/rpc/virnetserverprogram.h
+++ b/src/rpc/virnetserverprogram.h
@@ -1,7 +1,7 @@
 /*
  * virnetserverprogram.h: generic network RPC server program
  *
- * Copyright (C) 2006-2011 Red Hat, Inc.
+ * Copyright (C) 2006-2012, 2014-2015 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -31,6 +31,9 @@
 typedef struct _virNetServer virNetServer;
 typedef virNetServer *virNetServerPtr;

+typedef struct _virNetSubServer virNetSubServer;
+typedef virNetSubServer *virNetSubServerPtr;
+
 typedef struct _virNetServerService virNetServerService;
 typedef virNetServerService *virNetServerServicePtr;

@@ -40,7 +43,7 @@ typedef virNetServerProgram *virNetServerProgramPtr;
 typedef struct _virNetServerProgramProc virNetServerProgramProc;
 typedef virNetServerProgramProc *virNetServerProgramProcPtr;

-typedef int (*virNetServerProgramDispatchFunc)(virNetServerPtr server,
+typedef int (*virNetServerProgramDispatchFunc)(virNetSubServerPtr subserver,
                                                virNetServerClientPtr client,
                                                virNetMessagePtr msg,
                                                virNetMessageErrorPtr rerr,
@@ -72,7 +75,7 @@ int virNetServerProgramMatches(virNetServerProgramPtr prog,
                                virNetMessagePtr msg);

 int virNetServerProgramDispatch(virNetServerProgramPtr prog,
-                                virNetServerPtr server,
+                                virNetSubServerPtr subserver,
                                 virNetServerClientPtr client,
                                 virNetMessagePtr msg);

diff --git a/src/rpc/virnetsubserver.c b/src/rpc/virnetsubserver.c
new file mode 100644
index 0000000..8d9defb
--- /dev/null
+++ b/src/rpc/virnetsubserver.c
@@ -0,0 +1,662 @@
+/*
+ * virnetsubserver.c
+ *
+ * Copyright (C) 2014-2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Martin Kletzander <mkletzan@xxxxxxxxxx>
+ */
+
+
+#include <config.h>
+
+#include "virnetsubserver.h"
+
+#include "virlog.h"
+#include "viralloc.h"
+#include "virerror.h"
+#include "virthread.h"
+#include "virthreadpool.h"
+
+#define VIR_FROM_THIS VIR_FROM_RPC
+
+/*
+ * This file has been split from virnetserver.c and bothering people
+ * with the split and changing flters from "netserver" to
+ * "netsubserver" doesn't seem worthwhile, so we'll keep this as
+ * "netserver".
+ */
+VIR_LOG_INIT("rpc.netserver");
+
+
+typedef struct _virNetServerJob virNetServerJob;
+typedef virNetServerJob *virNetServerJobPtr;
+
+struct _virNetServerJob {
+    virNetServerClientPtr client;
+    virNetMessagePtr msg;
+    virNetServerProgramPtr prog;
+};
+
+struct _virNetSubServer {
+    virObjectLockable object;
+
+    virThreadPoolPtr workers;
+
+    size_t nservices;
+    virNetServerServicePtr *services;
+
+    size_t nprograms;
+    virNetServerProgramPtr *programs;
+
+    size_t nclients;                    /* Current clients count */
+    virNetServerClientPtr *clients;     /* Clients */
+    size_t nclients_max;                /* Max allowed clients count */
+    size_t nclients_unauth;             /* Unauthenticated clients count */
+    size_t nclients_unauth_max;         /* Max allowed unauth clients count */
+
+    int keepaliveInterval;
+    unsigned int keepaliveCount;
+    bool keepaliveRequired;
+
+    virNetServerClientPrivNew clientPrivNew;
+    virNetServerClientPrivPreExecRestart clientPrivPreExecRestart;
+    virFreeCallback clientPrivFree;
+    void *clientPrivOpaque;
+};
+
+
+static virClassPtr virNetSubServerClass;
+
+static void
+virNetSubServerDispose(void *obj)
+{
+    size_t i = 0;
+    virNetSubServerPtr subsrv = obj;
+
+    if (!subsrv)
+        return;
+
+    for (i = 0; i < subsrv->nservices; i++)
+        virNetServerServiceToggle(subsrv->services[i], false);
+
+    virThreadPoolFree(subsrv->workers);
+
+    for (i = 0; i < subsrv->nservices; i++)
+        virObjectUnref(subsrv->services[i]);
+    VIR_FREE(subsrv->services);
+
+    for (i = 0; i < subsrv->nprograms; i++)
+        virObjectUnref(subsrv->programs[i]);
+    VIR_FREE(subsrv->programs);
+
+    for (i = 0; i < subsrv->nclients; i++) {
+        virNetServerClientClose(subsrv->clients[i]);
+        virObjectUnref(subsrv->clients[i]);
+    }
+    VIR_FREE(subsrv->clients);
+}
+
+static int
+virNetSubServerOnceInit(void)
+{
+    if (!(virNetSubServerClass = virClassNew(virClassForObjectLockable(),
+                                             "virNetSubServer",
+                                             sizeof(virNetSubServer),
+                                             virNetSubServerDispose)))
+        return -1;
+
+    return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virNetSubServer)
+
+
+static inline size_t
+virNetSubServerTrackPendingAuthLocked(virNetSubServerPtr subsrv)
+{
+    return ++subsrv->nclients_unauth;
+}
+
+static inline size_t
+virNetSubServerTrackCompletedAuthLocked(virNetSubServerPtr subsrv)
+{
+    return --subsrv->nclients_unauth;
+}
+
+static int
+virNetSubServerProcessMsg(virNetSubServerPtr subsrv,
+                          virNetServerClientPtr client,
+                          virNetServerProgramPtr prog,
+                          virNetMessagePtr msg)
+{
+    int ret = -1;
+    if (!prog) {
+        /* Only send back an error for type == CALL. Other
+         * message types are not expecting replies, so we
+         * must just log it & drop them
+         */
+        if (msg->header.type == VIR_NET_CALL ||
+            msg->header.type == VIR_NET_CALL_WITH_FDS) {
+            if (virNetServerProgramUnknownError(client,
+                                                msg,
+                                                &msg->header) < 0)
+                goto cleanup;
+        } else {
+            VIR_INFO("Dropping client mesage, unknown program %d version %d type %d proc %d",
+                     msg->header.prog, msg->header.vers,
+                     msg->header.type, msg->header.proc);
+            /* Send a dummy reply to free up 'msg' & unblock client rx */
+            virNetMessageClear(msg);
+            msg->header.type = VIR_NET_REPLY;
+            if (virNetServerClientSendMessage(client, msg) < 0)
+                goto cleanup;
+        }
+        goto done;
+    }
+
+    if (virNetServerProgramDispatch(prog, subsrv, client, msg) < 0)
+        goto cleanup;
+
+ done:
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+static void virNetSubServerHandleJob(void *jobOpaque, void *opaque)
+{
+    virNetSubServerPtr subsrv = opaque;
+    virNetServerJobPtr job = jobOpaque;
+
+    VIR_DEBUG("subserver=%p client=%p message=%p prog=%p",
+              subsrv, job->client, job->msg, job->prog);
+
+    if (virNetSubServerProcessMsg(subsrv, job->client, job->prog, job->msg) < 0)
+        goto error;
+
+    virObjectUnref(job->prog);
+    virObjectUnref(job->client);
+    VIR_FREE(job);
+    return;
+
+ error:
+    virObjectUnref(job->prog);
+    virNetMessageFree(job->msg);
+    virNetServerClientClose(job->client);
+    virObjectUnref(job->client);
+    VIR_FREE(job);
+}
+
+static int
+virNetSubServerDispatchNewClient(virNetServerServicePtr svc,
+                                 virNetSocketPtr clientsock,
+                                 void *opaque)
+{
+    virNetSubServerPtr subsrv = opaque;
+    virNetServerClientPtr client;
+
+    if (!(client = virNetServerClientNew(clientsock,
+                                         virNetServerServiceGetAuth(svc),
+                                         virNetServerServiceIsReadonly(svc),
+                                         virNetServerServiceGetMaxRequests(svc),
+#if WITH_GNUTLS
+                                         virNetServerServiceGetTLSContext(svc),
+#endif
+                                         subsrv->clientPrivNew,
+                                         subsrv->clientPrivPreExecRestart,
+                                         subsrv->clientPrivFree,
+                                         subsrv->clientPrivOpaque)))
+        return -1;
+
+    if (virNetSubServerAddClient(subsrv, client) < 0) {
+        virNetServerClientClose(client);
+        virObjectUnref(client);
+        return -1;
+    }
+    virObjectUnref(client);
+    return 0;
+}
+
+static void
+virNetSubServerUpdateServicesLocked(virNetSubServerPtr subsrv,
+                                    bool enabled)
+{
+    size_t i = 0;
+
+    for (i = 0; i < subsrv->nservices; i++)
+        virNetServerServiceToggle(subsrv->services[i], enabled);
+}
+
+void
+virNetSubServerUpdateServices(virNetSubServerPtr subsrv,
+                              bool enabled)
+{
+    virObjectLock(subsrv);
+    virNetSubServerUpdateServicesLocked(subsrv, enabled);
+    virObjectUnlock(subsrv);
+}
+
+/**
+ * virNetSubServerCheckLimits:
+ * @srv: server to check limits on
+ *
+ * Check if limits like max_clients or max_anonymous_clients
+ * are satisfied and if so, re-enable accepting new clients.
+ * The @srv must be locked when this function is called.
+ */
+static void
+virNetSubServerCheckLimits(virNetSubServerPtr subsrv)
+{
+    /* Enable services if we can accept a new client.
+     * The new client can be accepted if both max_clients and
+     * max_anonymous_clients wouldn't get overcommitted by
+     * accepting it. */
+    VIR_DEBUG("Considering re-enabling services: "
+              "nclients=%zu nclients_max=%zu "
+              "nclients_unauth=%zu nclients_unauth_max=%zu",
+              subsrv->nclients, subsrv->nclients_max,
+              subsrv->nclients_unauth, subsrv->nclients_unauth_max);
+    if (subsrv->nclients < subsrv->nclients_max &&
+        (!subsrv->nclients_unauth_max ||
+         subsrv->nclients_unauth < subsrv->nclients_unauth_max)) {
+        /* Now it makes sense to accept() a new client. */
+        VIR_INFO("Re-enabling services");
+        virNetSubServerUpdateServicesLocked(subsrv, true);
+    }
+}
+
+static int
+virNetSubServerDispatchNewMessage(virNetServerClientPtr client,
+                                  virNetMessagePtr msg,
+                                  void *opaque)
+{
+    virNetSubServerPtr subsrv = opaque;
+    virNetServerProgramPtr prog = NULL;
+    unsigned int priority = 0;
+    size_t i;
+    int ret = -1;
+
+    VIR_DEBUG("subserver=%p client=%p message=%p",
+              subsrv, client, msg);
+
+    virObjectLock(subsrv);
+    for (i = 0; i < subsrv->nprograms; i++) {
+        if (virNetServerProgramMatches(subsrv->programs[i], msg)) {
+            prog = subsrv->programs[i];
+            break;
+        }
+    }
+
+    if (subsrv->workers) {
+        virNetServerJobPtr job;
+
+        if (VIR_ALLOC(job) < 0)
+            goto cleanup;
+
+        job->client = client;
+        job->msg = msg;
+
+        if (prog) {
+            virObjectRef(prog);
+            job->prog = prog;
+            priority = virNetServerProgramGetPriority(prog, msg->header.proc);
+        }
+
+        ret = virThreadPoolSendJob(subsrv->workers, priority, job);
+
+        if (ret < 0) {
+            VIR_FREE(job);
+            virObjectUnref(prog);
+        }
+    } else {
+        ret = virNetSubServerProcessMsg(subsrv, client, prog, msg);
+    }
+
+ cleanup:
+    virObjectUnlock(subsrv);
+
+    return ret;
+}
+
+virNetSubServerPtr
+virNetSubServerNew(size_t min_workers,
+                   size_t max_workers,
+                   size_t priority_workers,
+                   size_t max_clients,
+                   size_t max_anonymous_clients,
+                   int keepaliveInterval,
+                   unsigned int keepaliveCount,
+                   bool keepaliveRequired,
+                   virNetServerClientPrivNew cpNew,
+                   virNetServerClientPrivPreExecRestart cpPreExecRestart,
+                   virFreeCallback cpFree,
+                   void *cpOpaque)
+{
+    virNetSubServerPtr subsrv = NULL;
+
+    if (virNetSubServerInitialize() < 0)
+        return NULL;
+
+    if (!(subsrv = virObjectLockableNew(virNetSubServerClass)))
+        return NULL;
+
+    subsrv->nclients_max = max_clients;
+    subsrv->nclients_unauth_max = max_anonymous_clients;
+    subsrv->clientPrivNew = cpNew;
+    subsrv->clientPrivPreExecRestart = cpPreExecRestart;
+    subsrv->clientPrivFree = cpFree;
+    subsrv->clientPrivOpaque = cpOpaque;
+    subsrv->keepaliveInterval = keepaliveInterval;
+    subsrv->keepaliveCount = keepaliveCount;
+    subsrv->keepaliveRequired = keepaliveRequired;
+
+    if (max_workers &&
+        !(subsrv->workers = virThreadPoolNew(min_workers, max_workers,
+                                             priority_workers,
+                                             virNetSubServerHandleJob,
+                                             subsrv)))
+        goto error;
+
+    return subsrv;
+ error:
+    virObjectUnref(subsrv);
+    return NULL;
+}
+
+int
+virNetSubServerAddClient(virNetSubServerPtr subsrv,
+                         virNetServerClientPtr client)
+{
+    virObjectLock(subsrv);
+
+    if (subsrv->nclients >= subsrv->nclients_max) {
+        virReportError(VIR_ERR_RPC,
+                       _("Too many active clients (%zu), dropping connection from %s"),
+                       subsrv->nclients_max, virNetServerClientRemoteAddrString(client));
+        goto error;
+    }
+
+    if (virNetServerClientInit(client) < 0)
+        goto error;
+
+    if (VIR_EXPAND_N(subsrv->clients, subsrv->nclients, 1) < 0)
+        goto error;
+    subsrv->clients[subsrv->nclients-1] = client;
+    virObjectRef(client);
+
+    if (virNetServerClientNeedAuth(client))
+        virNetSubServerTrackPendingAuthLocked(subsrv);
+
+    if (subsrv->nclients_unauth_max &&
+        subsrv->nclients_unauth == subsrv->nclients_unauth_max) {
+        /* Temporarily stop accepting new clients */
+        VIR_INFO("Temporarily suspending services "
+                  "due to max_anonymous_clients");
+        virNetSubServerUpdateServicesLocked(subsrv, false);
+    }
+
+    if (subsrv->nclients == subsrv->nclients_max) {
+        /* Temporarily stop accepting new clients */
+        VIR_INFO("Temporarily suspending services due to max_clients");
+        virNetSubServerUpdateServicesLocked(subsrv, false);
+    }
+
+    virNetServerClientSetDispatcher(client,
+                                    virNetSubServerDispatchNewMessage,
+                                    subsrv);
+
+    virNetServerClientInitKeepAlive(client, subsrv->keepaliveInterval,
+                                    subsrv->keepaliveCount);
+
+    virObjectUnlock(subsrv);
+    return 0;
+
+ error:
+    virObjectUnlock(subsrv);
+    return -1;
+}
+
+virJSONValuePtr
+virNetSubServerPreExecRestart(virNetSubServerPtr subsrv)
+{
+    size_t i;
+    virJSONValuePtr clients = NULL;
+    virJSONValuePtr object = NULL;
+    virJSONValuePtr ret = NULL;
+    virJSONValuePtr services = NULL;
+
+    if (!(object = virJSONValueNewObject()))
+        goto error;
+
+    if (virJSONValueObjectAppendNumberUint(object, "min_workers",
+                                           virThreadPoolGetMinWorkers(subsrv->workers)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set min_workers data in JSON document"));
+        goto error;
+    }
+    if (virJSONValueObjectAppendNumberUint(object, "max_workers",
+                                           virThreadPoolGetMaxWorkers(subsrv->workers)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set max_workers data in JSON document"));
+        goto error;
+    }
+    if (virJSONValueObjectAppendNumberUint(object, "priority_workers",
+                                           virThreadPoolGetPriorityWorkers(subsrv->workers)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set priority_workers data in JSON document"));
+        goto error;
+    }
+    if (virJSONValueObjectAppendNumberUint(object, "max_clients", subsrv->nclients_max) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set max_clients data in JSON document"));
+        goto error;
+    }
+    if (virJSONValueObjectAppendNumberUint(object, "max_anonymous_clients",
+                                           subsrv->nclients_unauth_max) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set max_anonymous_clients data in JSON document"));
+        goto error;
+    }
+    if (virJSONValueObjectAppendNumberUint(object, "keepaliveInterval", subsrv->keepaliveInterval) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set keepaliveInterval data in JSON document"));
+        goto error;
+    }
+    if (virJSONValueObjectAppendNumberUint(object, "keepaliveCount", subsrv->keepaliveCount) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set keepaliveCount data in JSON document"));
+        goto error;
+    }
+    if (virJSONValueObjectAppendBoolean(object, "keepaliveRequired", subsrv->keepaliveRequired) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot set keepaliveRequired data in JSON document"));
+        goto error;
+    }
+
+    services = virJSONValueNewArray();
+    if (virJSONValueObjectAppend(object, "services", services) < 0) {
+        virJSONValueFree(services);
+        goto error;
+    }
+
+    for (i = 0; i < subsrv->nservices; i++) {
+        virJSONValuePtr child;
+        if (!(child = virNetServerServicePreExecRestart(subsrv->services[i])))
+            goto error;
+
+        if (virJSONValueArrayAppend(services, child) < 0) {
+            virJSONValueFree(child);
+            goto error;
+        }
+    }
+
+    clients = virJSONValueNewArray();
+    if (virJSONValueObjectAppend(object, "clients", clients) < 0) {
+        virJSONValueFree(clients);
+        goto error;
+    }
+
+    for (i = 0; i < subsrv->nclients; i++) {
+        virJSONValuePtr child;
+        if (!(child = virNetServerClientPreExecRestart(subsrv->clients[i])))
+            goto error;
+
+        if (virJSONValueArrayAppend(clients, child) < 0) {
+            virJSONValueFree(child);
+            goto error;
+        }
+    }
+
+    ret = object;
+    object = NULL;
+ error:
+    virJSONValueFree(object);
+    return ret;
+}
+
+int
+virNetSubServerAddService(virNetSubServerPtr subsrv,
+                          virNetServerServicePtr svc)
+{
+    int ret = -1;
+
+    virObjectLock(subsrv);
+
+    if (VIR_APPEND_ELEMENT_COPY(subsrv->services, subsrv->nservices, svc) < 0)
+        goto cleanup;
+
+    virNetServerServiceSetDispatcher(svc,
+                                     virNetSubServerDispatchNewClient,
+                                     subsrv);
+
+    virObjectRef(svc);
+
+    ret = 0;
+ cleanup:
+    virObjectUnlock(subsrv);
+    return ret;
+}
+
+int
+virNetSubServerAddProgram(virNetSubServerPtr subsrv,
+                          virNetServerProgramPtr prog)
+{
+    int ret = -1;
+
+    virObjectLock(subsrv);
+
+    if (VIR_APPEND_ELEMENT_COPY(subsrv->programs, subsrv->nprograms, prog) < 0)
+        goto cleanup;
+
+    virObjectRef(prog);
+
+    ret = 0;
+ cleanup:
+    virObjectUnlock(subsrv);
+    return ret;
+}
+
+void
+virNetSubServerClose(virNetSubServerPtr subsrv)
+{
+    size_t i;
+
+    virObjectLock(subsrv);
+
+    for (i = 0; i < subsrv->nservices; i++)
+        virNetServerServiceClose(subsrv->services[i]);
+
+    virObjectUnlock(subsrv);
+}
+
+bool virNetSubServerKeepAliveRequired(virNetSubServerPtr subsrv)
+{
+    bool required;
+    virObjectLock(subsrv);
+    required = subsrv->keepaliveRequired;
+    virObjectUnlock(subsrv);
+    return required;
+}
+
+size_t
+virNetSubServerTrackPendingAuth(virNetSubServerPtr subsrv)
+{
+    size_t ret;
+    virObjectLock(subsrv);
+    ret = virNetSubServerTrackPendingAuthLocked(subsrv);
+    virObjectUnlock(subsrv);
+    return ret;
+}
+
+size_t
+virNetSubServerTrackCompletedAuth(virNetSubServerPtr subsrv)
+{
+    size_t ret;
+    virObjectLock(subsrv);
+    ret = virNetSubServerTrackCompletedAuthLocked(subsrv);
+    virNetSubServerCheckLimits(subsrv);
+    virObjectUnlock(subsrv);
+    return ret;
+}
+
+bool
+virNetSubServerHasClients(virNetSubServerPtr subsrv)
+{
+    bool ret;
+
+    virObjectLock(subsrv);
+    ret = !!subsrv->nclients;
+    virObjectUnlock(subsrv);
+
+    return ret;
+}
+
+void
+virNetSubServerProcessClients(virNetSubServerPtr subsrv)
+{
+    size_t i;
+
+    virObjectLock(subsrv);
+
+ reprocess:
+    for (i = 0; i < subsrv->nclients; i++) {
+        /* Coverity 5.3.0 couldn't see that subsrv->clients is non-NULL
+         * if subsrv->nclients is non-zero.  */
+        sa_assert(subsrv->clients);
+        if (virNetServerClientWantClose(subsrv->clients[i]))
+            virNetServerClientClose(subsrv->clients[i]);
+        if (virNetServerClientIsClosed(subsrv->clients[i])) {
+            virNetServerClientPtr client = subsrv->clients[i];
+
+            VIR_DELETE_ELEMENT(subsrv->clients, i, subsrv->nclients);
+
+            if (virNetServerClientNeedAuth(client))
+                virNetSubServerTrackCompletedAuthLocked(subsrv);
+
+            virNetSubServerCheckLimits(subsrv);
+
+            virObjectUnlock(subsrv);
+            virObjectUnref(client);
+            virObjectLock(subsrv);
+
+            goto reprocess;
+        }
+    }
+
+    virObjectUnlock(subsrv);
+}
diff --git a/src/rpc/virnetsubserver.h b/src/rpc/virnetsubserver.h
new file mode 100644
index 0000000..cf7c213
--- /dev/null
+++ b/src/rpc/virnetsubserver.h
@@ -0,0 +1,76 @@
+/*
+ * virnetsubserver.h
+ *
+ * Copyright (C) 2014-2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Martin Kletzander <mkletzan@xxxxxxxxxx>
+ */
+
+#ifndef __VIR_NET_SUBSERVER_H__
+# define __VIR_NET_SUBSERVER_H__
+
+
+# include <unistd.h>
+
+# include "virjson.h"
+# include "virnetserverclient.h"
+# include "virnetserverprogram.h"
+# include "virnetserverservice.h"
+# include "virobject.h"
+
+
+
+typedef struct _virNetSubServer virNetSubServer;
+typedef virNetSubServer *virNetSubServerPtr;
+
+
+virNetSubServerPtr
+virNetSubServerNew(size_t min_workers,
+                   size_t max_workers,
+                   size_t priority_workers,
+                   size_t max_clients,
+                   size_t max_anonymous_clients,
+                   int keepaliveInterval,
+                   unsigned int keepaliveCount,
+                   bool keepaliveRequired,
+                   virNetServerClientPrivNew cpNew,
+                   virNetServerClientPrivPreExecRestart cpPreExecRestart,
+                   virFreeCallback cpFree,
+                   void *cpOpaque);
+
+void virNetSubServerClose(virNetSubServerPtr subsrv);
+
+virJSONValuePtr virNetSubServerPreExecRestart(virNetSubServerPtr subsrv);
+
+int virNetSubServerAddService(virNetSubServerPtr subsrv,
+                              virNetServerServicePtr svc);
+int virNetSubServerAddProgram(virNetSubServerPtr subsrv,
+                              virNetServerProgramPtr prog);
+int virNetSubServerAddClient(virNetSubServerPtr subsrv,
+                             virNetServerClientPtr client);
+
+bool virNetSubServerKeepAliveRequired(virNetSubServerPtr subsrv);
+
+size_t virNetSubServerTrackPendingAuth(virNetSubServerPtr subsrv);
+size_t virNetSubServerTrackCompletedAuth(virNetSubServerPtr subsrv);
+
+bool virNetSubServerHasClients(virNetSubServerPtr subsrv);
+void virNetSubServerProcessClients(virNetSubServerPtr subsrv);
+
+void virNetSubServerUpdateServices(virNetSubServerPtr subsrv, bool enabled);
+
+#endif /* __VIR_NET_SUBSERVER_H__ */
-- 
2.3.5

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]