Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50816)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50817)
@@ -15,4 +15,5 @@
 #include "cr_vreg.h"
 #include "cr_blitter.h"
+#include "cr_htable.h"
 #include "spu_dispatch_table.h"
 #include "cr_dump.h"
@@ -354,8 +355,11 @@
     int          screenCount;
 
+    GLboolean fCrCmdEnabled;
+
     int numClients;
     CRClient *clients[CR_MAX_CLIENTS];  /**< array [numClients] */
     CRClient *curClient;
     CRClientNode *pCleanupClient;  /*list of clients with pending clean up*/
+    CRHTABLE clientTable;
     CRCurrentStatePointers current;
 
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c	(revision 50816)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c	(revision 50817)
@@ -62,4 +62,23 @@
 static DECLCALLBACK(int) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd);
 
+DECLINLINE(CRClient*) crVBoxServerClientById(uint32_t u32ClientID)
+{
+    int32_t i;
+
+    if (cr_server.fCrCmdEnabled)
+        return CrHTableGet(&cr_server.clientTable, u32ClientID);
+
+    for (i = 0; i < cr_server.numClients; i++)
+    {
+        if (cr_server.clients[i] && cr_server.clients[i]->conn
+            && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
+        {
+            return cr_server.clients[i];
+        }
+    }
+
+    return NULL;
+}
+
 DECLINLINE(int32_t) crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
 {
@@ -67,18 +86,10 @@
     int32_t i;
 
-    *ppClient = NULL;
-
-    for (i = 0; i < cr_server.numClients; i++)
-    {
-        if (cr_server.clients[i] && cr_server.clients[i]->conn
-            && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
-        {
-            pClient = cr_server.clients[i];
-            break;
-        }
-    }
+    pClient = crVBoxServerClientById(u32ClientID);
+
     if (!pClient)
     {
-        crWarning("client not found!");
+        WARN(("client not found!"));
+        *ppClient = NULL;
         return VERR_INVALID_PARAMETER;
     }
@@ -86,5 +97,6 @@
     if (!pClient->conn->vMajor)
     {
-        crWarning("no major version specified for client!");
+        WARN(("no major version specified for client!"));
+        *ppClient = NULL;
         return VERR_NOT_SUPPORTED;
     }
@@ -337,4 +349,7 @@
 #endif
 
+    cr_server.fCrCmdEnabled = GL_FALSE;
+    CrHTableCreate(&cr_server.clientTable, CR_MAX_CLIENTS);
+
     cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
 
@@ -441,4 +456,7 @@
 #endif
 
+    cr_server.fCrCmdEnabled = GL_FALSE;
+    CrHTableCreate(&cr_server.clientTable, CR_MAX_CLIENTS);
+
     cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
 
@@ -591,27 +609,6 @@
 }
 
-void crVBoxServerRemoveClient(uint32_t u32ClientID)
-{
-    CRClient *pClient=NULL;
-    int32_t i;
-
-    crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
-
-    for (i = 0; i < cr_server.numClients; i++)
-    {
-        if (cr_server.clients[i] && cr_server.clients[i]->conn
-            && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
-        {
-            pClient = cr_server.clients[i];
-            break;
-        }
-    }
-    //if (!pClient) return VERR_INVALID_PARAMETER;
-    if (!pClient)
-    {
-        crWarning("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID);
-        return;
-    }
-
+static void crVBoxServerRemoveClientObj(CRClient *pClient)
+{
 #ifdef VBOX_WITH_CRHGSMI
     CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
@@ -623,4 +620,40 @@
     /* Let server clear client from the queue */
     crServerDeleteClient(pClient);
+}
+
+static void crVBoxServerRemoveAllClients()
+{
+    int32_t i;
+    for (i = cr_server.numClients - 1; i >= 0; --i)
+    {
+        Assert(cr_server.clients[i]);
+        crVBoxServerRemoveClientObj(cr_server.clients[i]);
+    }
+}
+
+void crVBoxServerRemoveClient(uint32_t u32ClientID)
+{
+    CRClient *pClient=NULL;
+    int32_t i;
+
+    crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
+
+    for (i = 0; i < cr_server.numClients; i++)
+    {
+        if (cr_server.clients[i] && cr_server.clients[i]->conn
+            && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
+        {
+            pClient = cr_server.clients[i];
+            break;
+        }
+    }
+    //if (!pClient) return VERR_INVALID_PARAMETER;
+    if (!pClient)
+    {
+        WARN(("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID));
+        return;
+    }
+
+    crVBoxServerRemoveClientObj(pClient);
 }
 
@@ -3263,8 +3296,13 @@
 static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
 {
+    Assert(!cr_server.fCrCmdEnabled);
+    Assert(!cr_server.numClients);
+
     cr_server.CrCmdClientInfo = *pInfo;
 
     crVBoxServerDefaultContextSet();
 
+    cr_server.fCrCmdEnabled = GL_TRUE;
+
     return VINF_SUCCESS;
 }
@@ -3272,8 +3310,16 @@
 static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr)
 {
+    Assert(cr_server.fCrCmdEnabled);
+
+    crVBoxServerRemoveAllClients();
+
+    CrHTableEmpty(&cr_server.clientTable);
+
     cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
 
     memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo));
 
+    cr_server.fCrCmdEnabled = GL_FALSE;
+
     return VINF_SUCCESS;
 }
@@ -3282,4 +3328,51 @@
 {
     return crVBoxServerHostCtl((VBOXCRCMDCTL*)pCmd, cbCmd);
+}
+
+static int crVBoxCrDisconnect(uint32_t u32Client)
+{
+    CRClient *pClient = (CRClient*)CrHTableRemove(&cr_server.clientTable, u32Client);
+    if (!pClient)
+    {
+        WARN(("invalid client id"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    crVBoxServerRemoveClientObj(pClient);
+
+    return VINF_SUCCESS;
+}
+
+static int crVBoxCrConnect(VBOXCMDVBVA_3DCTL_CONNECT *pConnect)
+{
+    CRClient *pClient;
+    int rc;
+    /* allocate client id */
+    uint32_t u32ClientId =  CrHTablePut(&cr_server.clientTable, (void*)1);
+    if (u32ClientId != CRHTABLE_HANDLE_INVALID)
+    {
+        rc = crVBoxServerAddClientObj(u32ClientId, &pClient);
+        if (RT_SUCCESS(rc))
+        {
+            rc = CrHTablePutToSlot(&cr_server.clientTable, u32ClientId, pClient);
+            if (RT_SUCCESS(rc))
+                return VINF_SUCCESS;
+            else
+                WARN(("CrHTablePutToSlot failed %d", rc));
+
+            crVBoxServerRemoveClientObj(pClient);
+        }
+        else
+            WARN(("crVBoxServerAddClientObj failed %d", rc));
+
+        CrHTableRemove(&cr_server.clientTable, u32ClientId);
+    }
+    else
+    {
+        WARN(("CrHTablePut failed"));
+        rc = VERR_NO_MEMORY;
+    }
+
+    return rc;
 }
 
@@ -3297,11 +3390,21 @@
         case VBOXCMDVBVA3DCTL_TYPE_CONNECT:
         {
-            VBOXCMDVBVA_3DCTL_CONNECT *pConnect = (VBOXCMDVBVA_3DCTL_CONNECT*)pCtl;
-
-            return VERR_NOT_SUPPORTED;
+            if (cbCmd != sizeof (VBOXCMDVBVA_3DCTL_CONNECT))
+            {
+                WARN(("invalid command size"));
+                return VERR_INVALID_PARAMETER;
+            }
+
+            return crVBoxCrConnect((VBOXCMDVBVA_3DCTL_CONNECT*)pCtl);
         }
         case VBOXCMDVBVA3DCTL_TYPE_DISCONNECT:
         {
-            return VERR_NOT_SUPPORTED;
+            if (cbCmd != sizeof (VBOXCMDVBVA_3DCTL))
+            {
+                WARN(("invalid command size"));
+                return VERR_INVALID_PARAMETER;
+            }
+
+            return crVBoxCrDisconnect(pCtl->u32CmdClientId);
         }
         case VBOXCMDVBVA3DCTL_TYPE_CMD:
@@ -3778,4 +3881,6 @@
     uint32_t cbCtl;
 
+    Assert(!cr_server.fCrCmdEnabled);
+
     if (cr_server.numClients)
     {
@@ -3796,4 +3901,6 @@
 int32_t crVBoxServerHgcmDisable()
 {
+    Assert(!cr_server.fCrCmdEnabled);
+
     if (cr_server.numClients)
     {
