Index: trunk/src/VBox/GuestHost/OpenGL/Makefile.kmk
===================================================================
--- trunk/src/VBox/GuestHost/OpenGL/Makefile.kmk	(revision 33093)
+++ trunk/src/VBox/GuestHost/OpenGL/Makefile.kmk	(revision 33116)
@@ -77,4 +77,5 @@
 	util/warp.c \
 	util/vboxhgcm.c \
+	$(if $(VBOX_WITH_CRHGSMI),util/vboxhgsmi.c,) \
 	$(VBOX_PATH_CROGL_GENFILES)/debug_opcodes.c
 VBoxOGLcrutil_SOURCES.win.x86 = \
@@ -88,4 +89,8 @@
 	$(VBOX_LIB_VBGL_R3_SHARED) \
 	$(VBOX_LIB_IPRT_GUEST_R3_SHARED)
+ifdef VBOX_WITH_CRHGSMI
+VBoxOGLcrutil_DEFS    += VBOX_WITH_CRHGSMI 
+VBoxOGLcrutil_LIBS    += $(VBOX_PATH_ADDITIONS_LIB)/VBoxCrHgsmi$(VBOX_SUFF_LIB)
+endif
 VBoxOGLcrutil_CLEAN = \
 	$(VBOX_PATH_CROGL_GENFILES)/debug_opcodes.c
Index: trunk/src/VBox/GuestHost/OpenGL/util/net.c
===================================================================
--- trunk/src/VBox/GuestHost/OpenGL/util/net.c	(revision 33093)
+++ trunk/src/VBox/GuestHost/OpenGL/util/net.c	(revision 33116)
@@ -56,4 +56,7 @@
     int                  use_tcscomm;
     int                  use_hgcm;
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+    int                  use_hgsmi;
+#endif
 
     int                  num_clients; /* total number of clients (unused?) */
@@ -109,7 +112,19 @@
     else if (!crStrcmp(protocol, "vboxhgcm"))
     {
-        cr_net.use_hgcm++;
-        crVBoxHGCMInit(cr_net.recv_list, cr_net.close_list, mtu);
-        crVBoxHGCMConnection(conn);
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+        /* for now just use hgcm protocol name
+         * since we still partially use HGCM and have HGCM backend on the host side */
+        if(crVBoxHGSMIInit(cr_net.recv_list, cr_net.close_list, mtu))
+        {
+            cr_net.use_hgsmi++;
+            crVBoxHGSMIConnection(conn);
+        }
+        else
+# endif /* # #if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST) */
+        {
+            cr_net.use_hgcm++;
+            crVBoxHGCMInit(cr_net.recv_list, cr_net.close_list, mtu);
+            crVBoxHGCMConnection(conn);
+        }
     }
 #endif
@@ -433,4 +448,7 @@
         cr_net.use_hgcm    = 0;
         cr_net.num_clients = 0;
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+        cr_net.use_hgsmi = 0;
+#endif
 #ifdef CHROMIUM_THREADSAFE
         crInitMutex(&cr_net.mutex);
@@ -498,4 +516,8 @@
 #endif
 
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+    if (cr_net.use_hgsmi)
+        crVBoxHGSMITearDown();
+#endif
     /* Note, other protocols used by chromium should free up stuff too,
      * but VBox doesn't use them, so no other checks.
@@ -537,4 +559,8 @@
     if ( c ) return c;
 
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+    c = crVBoxHGSMIDump( num );
+    if ( c ) return c;
+#endif
 #ifdef VBOX_WITH_HGCM
     c = crVBoxHGCMDump( num );
@@ -1239,4 +1265,8 @@
     if ( cr_net.use_tcpip )
         found_work += crTCPIPRecv();
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+    if (cr_net.use_hgsmi)
+        found_work += crVBoxHGSMIRecv();
+#endif
 #ifdef VBOX_WITH_HGCM
     if ( cr_net.use_hgcm )
Index: trunk/src/VBox/GuestHost/OpenGL/util/net_internals.h
===================================================================
--- trunk/src/VBox/GuestHost/OpenGL/util/net_internals.h	(revision 33093)
+++ trunk/src/VBox/GuestHost/OpenGL/util/net_internals.h	(revision 33116)
@@ -97,4 +97,11 @@
 extern void crVBoxHGCMTearDown(void);
 #endif
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+extern bool crVBoxHGSMIInit( CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu );
+extern void crVBoxHGSMIConnection( CRConnection *conn );
+extern int crVBoxHGSMIRecv( void );
+extern CRConnection** crVBoxHGSMIDump( int *num );
+extern void crVBoxHGSMITearDown(void);
+#endif /* #if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST) */
 
 /*
Index: trunk/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c
===================================================================
--- trunk/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c	(revision 33116)
+++ trunk/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c	(revision 33116)
@@ -0,0 +1,1344 @@
+/* $Id$ */
+
+/** @file
+ * VBox HGCM connection
+ */
+
+/*
+ * Copyright (C) 2008 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+//#define IN_GUEST
+#ifdef IN_GUEST
+#ifdef RT_OS_WINDOWS
+    #include <windows.h>
+    #include <ddraw.h>
+#else
+    #include <sys/ioctl.h>
+    #include <errno.h>
+    #include <fcntl.h>
+    #include <string.h>
+    #include <unistd.h>
+#endif
+
+#include "cr_error.h"
+#include "cr_net.h"
+#include "cr_bufpool.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+#include "cr_endian.h"
+#include "cr_threads.h"
+#include "net_internals.h"
+
+#include <iprt/thread.h>
+
+#include <VBox/VBoxCrHgsmi.h>
+#if 1 /** @todo Try use the Vbgl interface instead of talking directly to the driver? */
+# include <VBox/VBoxGuest.h>
+#else
+# include <VBox/VBoxGuestLib.h>
+#endif
+#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
+
+#ifndef IN_GUEST
+# error "Hgsmi is supported for guest lib only!!"
+#endif
+
+typedef struct {
+    int                  initialized;
+    int                  num_conns;
+    CRConnection         **conns;
+#ifdef CHROMIUM_THREADSAFE
+    CRmutex              mutex;
+    CRmutex              recvmutex;
+#endif
+    CRNetReceiveFuncList *recv_list;
+    CRNetCloseFuncList   *close_list;
+    CRBufferPool *mempool;
+#ifdef RT_OS_WINDOWS
+    HANDLE               hGuestDrv;
+#else
+    int                  iGuestDrv;
+#endif
+} CRVBOXHGSMIDATA;
+
+#define CR_VBOXHGSMI_BUFFER_MAGIC 0xEDCBA123
+
+typedef struct CRVBOXHGSMIBUFFER {
+    uint32_t             magic;
+    union
+    {
+        struct
+        {
+            uint32_t             cbLock : 31;
+            uint32_t             bIsBuf : 1;
+        };
+        uint32_t Value;
+    };
+    union
+    {
+        PVBOXUHGSMI_BUFFER pBuffer;
+        uint32_t u32Len; /* <- sys mem buf specific */
+        uint64_t u64Align;
+    };
+} CRVBOXHGSMIBUFFER;
+
+typedef struct CRVBOXHGSMI_CLIENT {
+    PVBOXUHGSMI pHgsmi;
+    PVBOXUHGSMI_BUFFER pCmdBuffer;
+    PVBOXUHGSMI_BUFFER pHGBuffer;
+    void *pvHGBuffer;
+    CRBufferPool *bufpool;
+} CRVBOXHGSMI_CLIENT, *PCRVBOXHGSMI_CLIENT;
+
+
+static CRVBOXHGSMIDATA g_crvboxhgsmi = {0,};
+
+DECLINLINE(PCRVBOXHGSMI_CLIENT) _crVBoxHGSMIClientGet()
+{
+    return (PCRVBOXHGSMI_CLIENT)VBoxCrHgsmiQueryClient();
+}
+
+#ifndef RT_OS_WINDOWS
+    #define TRUE true
+    #define FALSE false
+    #define INVALID_HANDLE_VALUE (-1)
+#endif
+
+/* Some forward declarations */
+static void _crVBoxHGSMIReceiveMessage(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient);
+
+/* we still use hgcm for establishing the connection
+ * @todo: join the common code of HGSMI & HGCM */
+/**
+ * Send an HGCM request
+ *
+ * @return VBox status code
+ * @param   pvData      Data pointer
+ * @param   cbData      Data size
+ */
+/** @todo use vbglR3DoIOCtl here instead */
+static int crVBoxHGCMCall(void *pvData, unsigned cbData)
+{
+#ifdef IN_GUEST
+
+# ifdef RT_OS_WINDOWS
+    DWORD cbReturned;
+
+    if (DeviceIoControl (g_crvboxhgsmi.hGuestDrv,
+                         VBOXGUEST_IOCTL_HGCM_CALL(cbData),
+                         pvData, cbData,
+                         pvData, cbData,
+                         &cbReturned,
+                         NULL))
+    {
+        return VINF_SUCCESS;
+    }
+    crDebug("vboxCall failed with %x\n", GetLastError());
+    return VERR_NOT_SUPPORTED;
+# else
+    int rc;
+#  if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+    VBGLBIGREQ Hdr;
+    Hdr.u32Magic = VBGLBIGREQ_MAGIC;
+    Hdr.cbData = cbData;
+    Hdr.pvDataR3 = pvData;
+#   if HC_ARCH_BITS == 32
+    Hdr.u32Padding = 0;
+#   endif
+    rc = ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), &Hdr);
+#  else
+    rc = ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
+#  endif
+#  ifdef RT_OS_LINUX
+    if (rc == 0)
+#  else
+    if (rc >= 0)
+#  endif
+    {
+        return VINF_SUCCESS;
+    }
+#  ifdef RT_OS_LINUX
+    if (rc >= 0) /* positive values are negated VBox error status codes. */
+    {
+        crWarning("vboxCall failed with VBox status code %d\n", -rc);
+        if (rc==VINF_INTERRUPTED)
+        {
+            RTMSINTERVAL sl;
+            int i;
+
+            for (i=0, sl=50; i<6; i++, sl=sl*2)
+            {
+                RTThreadSleep(sl);
+                rc = ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
+                if (rc==0)
+                {
+                    crWarning("vboxCall retry(%i) succeded", i+1);
+                    return VINF_SUCCESS;
+                }
+                else if (rc==VINF_INTERRUPTED)
+                {
+                    continue;
+                }
+                else
+                {
+                    crWarning("vboxCall retry(%i) failed with VBox status code %d", i+1, -rc);
+                    break;
+                }
+            }
+        }
+    }
+    else
+#  endif
+        crWarning("vboxCall failed with %x\n", errno);
+    return VERR_NOT_SUPPORTED;
+# endif /*#ifdef RT_OS_WINDOWS*/
+
+#else /*#ifdef IN_GUEST*/
+    crError("crVBoxHGCMCall called on host side!");
+    CRASSERT(FALSE);
+    return VERR_NOT_SUPPORTED;
+#endif
+}
+
+
+/* add sizeof header + page allign */
+#define CRVBOXHGSMI_PAGE_ALIGN(_s) (((_s)  + 0xfff) & ~0xfff)
+#define CRVBOXHGSMI_BUF_HDR_SIZE() (sizeof (CRVBOXHGSMIBUFFER))
+#define CRVBOXHGSMI_BUF_SIZE(_s) CRVBOXHGSMI_PAGE_ALIGN((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
+#define CRVBOXHGSMI_BUF_LOCK_SIZE(_s) ((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
+#define CRVBOXHGSMI_BUF_DATA(_p) ((void*)(((CRVBOXHGSMIBUFFER*)(_p)) + 1))
+#define CRVBOXHGSMI_BUF_HDR(_p) (((CRVBOXHGSMIBUFFER*)(_p)) - 1)
+#define CRVBOXHGSMI_BUF_OFFSET(_st2, _st1) ((uint32_t)(((uint8_t*)(_st2)) - ((uint8_t*)(_st1))))
+
+static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLock(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
+{
+    /* in theory it is OK to use one cmd buffer for asynch cmd submission
+     * because bDiscard flag should result in allocating a new memory backend if the
+     * allocation is still in use.
+     * However, NOTE: since one and the same semaphore synch event is used for completion notification,
+     * for the notification mechanism working as expected
+     * 1. host must complete commands in the same order as it receives them
+     * (to avoid situation when guest receives notification for another command completion)
+     * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
+     * 3. guest must wait for command completion in the same order as it submits them
+     * in case we can not satisfy any of the above, we should introduce multiple command buffers */
+    CRVBOXHGSMIHDR * pHdr;
+    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+    int rc;
+    fFlags.Value = 0;
+    fFlags.bDiscard = 1;
+    rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
+    if (RT_FAILURE(rc))
+        crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
+    return pHdr;
+}
+
+static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLockRo(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
+{
+    /* in theory it is OK to use one cmd buffer for asynch cmd submission
+     * because bDiscard flag should result in allocating a new memory backend if the
+     * allocation is still in use.
+     * However, NOTE: since one and the same semaphore synch event is used for completion notification,
+     * for the notification mechanism working as expected
+     * 1. host must complete commands in the same order as it receives them
+     * (to avoid situation when guest receives notification for another command completion)
+     * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
+     * 3. guest must wait for command completion in the same order as it submits them
+     * in case we can not satisfy any of the above, we should introduce multiple command buffers */
+    CRVBOXHGSMIHDR * pHdr;
+    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+    int rc;
+    fFlags.Value = 0;
+    fFlags.bReadOnly = 1;
+    rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
+    if (RT_FAILURE(rc))
+        crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
+    return pHdr;
+}
+
+static void _crVBoxHGSMICmdBufferUnlock(PCRVBOXHGSMI_CLIENT pClient)
+{
+    int rc = pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
+    if (RT_FAILURE(rc))
+        crWarning("Failed to Unlock the command buffer rc(%d)\n", rc);
+}
+
+static int32_t _crVBoxHGSMICmdBufferGetRc(PCRVBOXHGSMI_CLIENT pClient)
+{
+    CRVBOXHGSMIHDR * pHdr;
+    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+    int rc;
+    fFlags.Value = 0;
+    fFlags.bReadOnly = 1;
+    rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, sizeof (*pHdr), fFlags, (void**)&pHdr);
+    if (RT_FAILURE(rc))
+    {
+        crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", sizeof (*pHdr), rc);
+        return rc;
+    }
+
+    rc = pHdr->result;
+    pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
+
+    return rc;
+}
+
+static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufFromMemPtr(void *pvBuf)
+{
+    CRVBOXHGSMIBUFFER *pHdr = CRVBOXHGSMI_BUF_HDR(pvBuf);
+    PVBOXUHGSMI_BUFFER pBuf;
+    int rc;
+    CRASSERT(pHdr->magic == CR_VBOXHGSMI_BUFFER_MAGIC);
+    pBuf = pHdr->pBuffer;
+    rc = pBuf->pfnUnlock(pBuf);
+    if (RT_FAILURE(rc))
+    {
+        return NULL;
+    }
+    return pBuf;
+}
+
+static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
+{
+    PVBOXUHGSMI_BUFFER buf;
+    int rc;
+    buf = (PVBOXUHGSMI_BUFFER ) crBufferPoolPop(pClient->bufpool, cbSize);
+
+    if (!buf)
+    {
+        crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
+                        (void *) pClient->bufpool,
+                        cbSize);
+        rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, cbSize,
+                                VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL,
+                                &buf);
+        if (RT_FAILURE(rc))
+            crWarning("Failed to Create a buffer of size(%d), rc(%d)\n", cbSize, rc);
+    }
+    return buf;
+}
+
+static void _crVBoxHGSMIBufFree(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf)
+{
+    crBufferPoolPush(pClient->bufpool, pBuf, pBuf->cbBuffer);
+}
+
+static CRVBOXHGSMIBUFFER* _crVBoxHGSMISysMemAlloc(uint32_t cbSize)
+{
+    CRVBOXHGSMIBUFFER *pBuf;
+#ifdef CHROMIUM_THREADSAFE
+    crLockMutex(&g_crvboxhgsmi.mutex);
+#endif
+    pBuf = crBufferPoolPop(g_crvboxhgsmi.mempool, cbSize);
+    if (!pBuf)
+    {
+        pBuf = (CRVBOXHGSMIBUFFER*)crAlloc(CRVBOXHGSMI_BUF_HDR_SIZE() + cbSize);
+        if (pBuf)
+        {
+            pBuf->magic = CR_VBOXHGSMI_BUFFER_MAGIC;
+            pBuf->cbLock = cbSize;
+            pBuf->bIsBuf = false;
+            pBuf->u32Len = 0;
+        }
+    }
+#ifdef CHROMIUM_THREADSAFE
+    crUnlockMutex(&g_crvboxhgsmi.mutex);
+#endif
+    return pBuf;
+}
+
+static void *_crVBoxHGSMIDoAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
+{
+    PVBOXUHGSMI_BUFFER buf;
+    CRVBOXHGSMIBUFFER *pData = NULL;
+    int rc;
+
+    buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
+
+    if (buf)
+    {
+        VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+        buf->pvUserData = pClient;
+        fFlags.Value = 0;
+        fFlags.bDiscard = 1;
+        rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
+        if (RT_SUCCESS(rc))
+        {
+            pData->magic = CR_VBOXHGSMI_BUFFER_MAGIC;
+            pData->cbLock = CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize);
+            pData->bIsBuf = true;
+            pData->pBuffer = buf;
+        }
+        else
+        {
+            crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
+        }
+    }
+
+    return CRVBOXHGSMI_BUF_DATA(pData);
+
+}
+static void *crVBoxHGSMIAlloc(CRConnection *conn)
+{
+    PCRVBOXHGSMI_CLIENT pClient = _crVBoxHGSMIClientGet();
+    return _crVBoxHGSMIDoAlloc(pClient, conn->buffer_size);
+}
+
+DECLINLINE(void) _crVBoxHGSMIFillCmd(VBOXUHGSMI_BUFFER_SUBMIT *pSubm, PCRVBOXHGSMI_CLIENT pClient, uint32_t cbData)
+{
+    pSubm->pBuf = pClient->pCmdBuffer;
+    pSubm->offData = 0;
+    pSubm->cbData = cbData;
+    pSubm->fFlags.Value = 0;
+    pSubm->fFlags.bDoNotRetire = 1;
+    pSubm->fFlags.bDoNotSignalCompletion = 1; /* <- we do not need that actually since
+                                                       * in case we want completion,
+                                                       * we will block in _crVBoxHGSMICmdBufferGetRc (when locking the buffer)
+                                                       * which is needed for getting the result */
+}
+
+#ifdef RT_OS_WINDOWS
+#define CRVBOXHGSMI_BUF_WAIT(_pBub) WaitForSingleObject((_pBub)->hSynch, INFINITE);
+#else
+# error "Port Me!!"
+#endif
+
+static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
+{
+    int rc;
+    int32_t callRes;
+    VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
+
+#ifdef IN_GUEST
+    if (conn->u32InjectClientID)
+    {
+        CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
+        if (!parms)
+        {
+            return;
+        }
+
+        parms->hdr.result      = VERR_WRONG_ORDER;
+        parms->hdr.u32ClientID = conn->u32ClientID;
+        parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
+//        parms->hdr.u32Reserved = 0;
+
+        parms->u32ClientID = conn->u32InjectClientID;
+
+        parms->iBuffer = 1;
+        _crVBoxHGSMICmdBufferUnlock(pClient);
+
+        _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+        aSubmit[1].pBuf = pBuf;
+        aSubmit[1].offData = offStart;
+        aSubmit[1].cbData = len;
+        aSubmit[1].fFlags.Value = 0;
+        aSubmit[1].fFlags.bHostReadOnly = 1;
+
+        rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
+        if (RT_SUCCESS(rc))
+        {
+                /* @todo: do we need to wait for completion actually?
+                 * NOTE: in case we do not need completion,
+                 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
+//                CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
+
+            callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
+        }
+    }
+    else
+#endif
+    {
+        CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
+
+        parms->hdr.result      = VERR_WRONG_ORDER;
+        parms->hdr.u32ClientID = conn->u32ClientID;
+        parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
+//        parms->hdr.u32Reserved = 0;
+
+        parms->iBuffer = 1;
+        _crVBoxHGSMICmdBufferUnlock(pClient);
+
+        _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+        aSubmit[1].pBuf = pBuf;
+        aSubmit[1].offData = offStart;
+        aSubmit[1].cbData = len;
+        aSubmit[1].fFlags.Value = 0;
+        aSubmit[1].fFlags.bHostReadOnly = 1;
+
+        rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
+        if (RT_SUCCESS(rc))
+        {
+                /* @todo: do we need to wait for completion actually?
+                 * NOTE: in case we do not need completion,
+                 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
+//                CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
+
+            callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
+        }
+    }
+
+    if (RT_FAILURE(rc) || RT_FAILURE(callRes))
+    {
+        crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
+    }
+}
+
+static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
+{
+    CRASSERT(0);
+//    PCRVBOXHGSMI_CLIENT pClient;
+//    PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
+//    if (!pBuf)
+//        return;
+//    pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
+//    _crVBoxHGSMIWriteExact(conn, pClient, pBuf, 0, len);
+//    _crVBoxHGSMIBufFree(pClient, pBuf);
+}
+
+static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
+{
+    CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
+    int rc;
+    VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
+    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+    uint32_t cbBuffer;
+
+    parms->hdr.result      = VERR_WRONG_ORDER;
+    parms->hdr.u32ClientID = conn->u32ClientID;
+    parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
+//    parms->hdr.u32Reserved = 0;
+
+    CRASSERT(!conn->pBuffer); //make sure there's no data to process
+    parms->iBuffer = 1;
+    parms->cbBuffer = 0;
+
+    _crVBoxHGSMICmdBufferUnlock(pClient);
+
+    if (pClient->pvHGBuffer)
+    {
+        rc = pClient->pHGBuffer->pfnUnlock(pClient->pHGBuffer);
+        if (RT_FAILURE(rc))
+        {
+            return;
+        }
+        pClient->pvHGBuffer = NULL;
+    }
+
+    _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+    aSubmit[1].pBuf = pClient->pHGBuffer;
+    aSubmit[1].offData = 0;
+    aSubmit[1].cbData = pClient->pHGBuffer->cbBuffer;
+    aSubmit[1].fFlags.Value = 0;
+    aSubmit[1].fFlags.bHostWriteOnly = 1;
+
+    rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
+    if (RT_FAILURE(rc))
+    {
+        crWarning("pfnBufferSubmitAsynch failed with %d \n", rc);
+        return;
+    }
+
+    parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
+    if (!parms)
+    {
+        crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
+        return;
+    }
+
+    if (RT_SUCCESS(parms->hdr.result))
+        cbBuffer = parms->cbBuffer;
+    else
+        cbBuffer = 0;
+
+    _crVBoxHGSMICmdBufferUnlock(pClient);
+
+    if (cbBuffer)
+    {
+        fFlags.Value = 0;
+        rc = pClient->pHGBuffer->pfnLock(pClient->pHGBuffer, 0, cbBuffer, fFlags, &pClient->pvHGBuffer);
+        if (RT_SUCCESS(rc))
+        {
+            //conn->pBuffer  = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
+            conn->pBuffer  = pClient->pvHGBuffer;
+            conn->cbBuffer = cbBuffer;
+        }
+    }
+}
+
+static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
+{
+    _crVBoxHGSMIPollHost(conn, pClient);
+
+    if (conn->cbBuffer)
+        _crVBoxHGSMIReceiveMessage(conn, pClient);
+}
+
+/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
+ * This halves the number of HGCM calls we do,
+ * most likely crVBoxHGCMPollHost shouldn't be called at all now.
+ */
+static void
+_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
+{
+    CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
+    int rc;
+    VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
+    PVBOXUHGSMI_BUFFER pBuf = NULL;
+    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+//    uint32_t cbBuffer;
+
+    parms->hdr.result      = VERR_WRONG_ORDER;
+    parms->hdr.u32ClientID = conn->u32ClientID;
+    parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
+//    parms->hdr.u32Reserved = 0;
+
+    parms->iBuffer = 1;
+
+    CRASSERT(!conn->pBuffer); //make sure there's no data to process
+    parms->iWriteback = 2;
+    parms->cbWriteback = 0;
+
+    _crVBoxHGSMICmdBufferUnlock(pClient);
+
+    if (!bIsBuffer)
+    {
+        void *pvBuf;
+        pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
+        if (!pBuf)
+            return;
+
+        offBuffer = 0;
+        fFlags.Value = 0;
+        fFlags.bDiscard = 1;
+        fFlags.bWriteOnly = 1;
+        rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
+        if (RT_SUCCESS(rc))
+        {
+            memcpy(pvBuf, buf, len);
+            rc = pBuf->pfnUnlock(pBuf);
+            CRASSERT(rc);
+        }
+        else
+        {
+            _crVBoxHGSMIBufFree(pClient, pBuf);
+            return;
+        }
+    }
+
+    do
+    {
+        if (pClient->pvHGBuffer)
+        {
+            rc = pClient->pHGBuffer->pfnUnlock(pClient->pHGBuffer);
+            if (RT_FAILURE(rc))
+                break;
+            pClient->pvHGBuffer = NULL;
+        }
+
+        _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+        aSubmit[1].pBuf = pBuf;
+        aSubmit[1].offData = offBuffer;
+        aSubmit[1].cbData = len;
+        aSubmit[1].fFlags.Value = 0;
+        aSubmit[1].fFlags.bHostReadOnly = 1;
+
+        aSubmit[2].pBuf = pClient->pHGBuffer;
+        aSubmit[2].offData = 0;
+        aSubmit[2].cbData = pClient->pHGBuffer->cbBuffer;
+        aSubmit[2].fFlags.Value = 0;
+        aSubmit[2].fFlags.bHostWriteOnly = 1;
+
+        rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
+        if (RT_FAILURE(rc))
+        {
+            crWarning("pfnBufferSubmitAsynch failed with %d \n", rc);
+            break;
+        }
+
+        parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
+        if (parms)
+        {
+            if (VERR_BUFFER_OVERFLOW == parms->hdr.result)
+            {
+                PVBOXUHGSMI_BUFFER pOldBuf = pClient->pHGBuffer;
+                uint32_t cbWriteback = parms->cbWriteback;
+                CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
+                crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
+
+                rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback),
+                                VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL, &pClient->pHGBuffer);
+                CRASSERT(RT_SUCCESS(rc));
+                if (RT_SUCCESS(rc))
+                {
+                    rc = pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
+                    CRASSERT(RT_SUCCESS(rc));
+
+                    _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
+                }
+            }
+            else
+            {
+                crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x %x\n", len, rc, parms->hdr.result);
+            }
+
+            _crVBoxHGSMICmdBufferUnlock(pClient);
+        }
+        else
+        {
+            crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
+            break;
+        }
+    } while (0);
+
+    if (!bIsBuffer)
+        _crVBoxHGSMIBufFree(pClient, pBuf);
+}
+
+static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
+                           const void *start, unsigned int len)
+{
+    PCRVBOXHGSMI_CLIENT pClient;
+    PVBOXUHGSMI_BUFFER pBuf;
+
+    if (!bufp) /* We're sending a user-allocated buffer. */
+    {
+        pClient = _crVBoxHGSMIClientGet();
+#ifndef IN_GUEST
+            //@todo remove temp buffer allocation in unpacker
+            /* we're at the host side, so just store data until guest polls us */
+            _crVBoxHGCMWriteBytes(conn, start, len);
+#else
+            CRASSERT(!conn->u32InjectClientID);
+            crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
+            _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
+#endif
+        return;
+    }
+
+    /* The region [start .. start + len + 1] lies within a buffer that
+     * was allocated with crVBoxHGCMAlloc() and can be put into the free
+     * buffer pool when we're done sending it.
+     */
+
+    pBuf = _crVBoxHGSMIBufFromMemPtr(*bufp);
+    if (!pBuf)
+        return;
+
+    pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
+
+    /* Length would be passed as part of HGCM pointer description
+     * No need to prepend it to the buffer
+     */
+#ifdef IN_GUEST
+    if (conn->u32InjectClientID)
+    {
+        _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
+    }
+    else
+#endif
+    {
+        _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
+    }
+
+    /* Reclaim this pointer for reuse */
+    _crVBoxHGSMIBufFree(pClient, pBuf);
+    /* Since the buffer's now in the 'free' buffer pool, the caller can't
+     * use it any more.  Setting bufp to NULL will make sure the caller
+     * doesn't try to re-use the buffer.
+     */
+    *bufp = NULL;
+}
+
+static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
+{
+    PCRVBOXHGSMI_CLIENT pClient;
+    PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
+    CRASSERT(0);
+    if (!pBuf)
+        return;
+    pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
+    _crVBoxHGSMIReadExact(conn, pClient);
+}
+
+static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
+{
+    CRVBOXHGSMIBUFFER *hgsmi_buffer = (CRVBOXHGSMIBUFFER *) buf - 1;
+    CRASSERT(hgsmi_buffer->magic == CR_VBOXHGSMI_BUFFER_MAGIC);
+
+    if (hgsmi_buffer->bIsBuf)
+    {
+        PVBOXUHGSMI_BUFFER pBuf = hgsmi_buffer->pBuffer;
+        PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
+        pBuf->pfnUnlock(pBuf);
+        _crVBoxHGSMIBufFree(pClient, pBuf);
+    }
+    else
+    {
+        /*@todo wrong len for redir buffers*/
+        conn->recv_credits += hgsmi_buffer->u32Len;
+
+#ifdef CHROMIUM_THREADSAFE
+            crLockMutex(&g_crvboxhgsmi.mutex);
+#endif
+            crBufferPoolPush(g_crvboxhgsmi.mempool, hgsmi_buffer, hgsmi_buffer->cbLock);
+#ifdef CHROMIUM_THREADSAFE
+            crUnlockMutex(&g_crvboxhgsmi.mutex);
+#endif
+    }
+}
+
+static void _crVBoxHGSMIReceiveMessage(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
+{
+    uint32_t len;
+    CRVBOXHGSMIBUFFER* pSysBuf;
+    CRMessage *msg;
+    CRMessageType cached_type;
+
+    len = conn->cbBuffer;
+    CRASSERT(len > 0);
+    CRASSERT(conn->pBuffer);
+
+#ifndef IN_GUEST
+    if (conn->allow_redir_ptr)
+    {
+#endif //IN_GUEST
+        CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
+
+        pSysBuf = _crVBoxHGSMISysMemAlloc( conn->buffer_size );
+        pSysBuf->u32Len = sizeof(CRMessageRedirPtr);
+
+        msg = (CRMessage *)CRVBOXHGSMI_BUF_DATA(pSysBuf);
+
+        msg->header.type = CR_MESSAGE_REDIR_PTR;
+        msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
+        msg->header.conn_id = msg->redirptr.pMessage->conn_id;
+
+        cached_type = msg->redirptr.pMessage->type;
+
+        conn->cbBuffer = 0;
+        conn->pBuffer  = NULL;
+#ifndef IN_GUEST
+    }
+    else
+    {
+        if ( len <= conn->buffer_size )
+        {
+            /* put in pre-allocated buffer */
+            hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
+        }
+        else
+        {
+            /* allocate new buffer,
+             * not using pool here as it's most likely one time transfer of huge texture
+             */
+            hgcm_buffer            = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
+            hgcm_buffer->magic     = CR_VBOXHGCM_BUFFER_MAGIC;
+            hgcm_buffer->kind      = CR_VBOXHGCM_MEMORY_BIG;
+            hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
+# ifdef RT_OS_WINDOWS
+            hgcm_buffer->pDDS      = NULL;
+# endif
+        }
+
+        hgcm_buffer->len = len;
+
+        _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
+
+        msg = (CRMessage *) (hgcm_buffer + 1);
+        cached_type = msg->header.type;
+    }
+#endif //IN_GUEST
+
+    conn->recv_credits     -= len;
+    conn->total_bytes_recv += len;
+    conn->recv_count++;
+
+    crNetDispatchMessage( g_crvboxhgsmi.recv_list, conn, msg, len );
+
+    /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
+     * OOB messages are the programmer's problem.  -- Humper 12/17/01
+     */
+    if (cached_type != CR_MESSAGE_OPCODES
+        && cached_type != CR_MESSAGE_OOB
+        && cached_type != CR_MESSAGE_GATHER)
+    {
+        crVBoxHGSMIFree(conn, msg);
+    }
+}
+
+static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
+{
+    PCRVBOXHGSMI_CLIENT pClient = _crVBoxHGSMIClientGet();
+    _crVBoxHGSMIReceiveMessage(conn, pClient);
+}
+/*
+ * Called on host side only, to "accept" client connection
+ */
+static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
+{
+    CRASSERT(conn && conn->pHostBuffer);
+#ifdef IN_GUEST
+    CRASSERT(FALSE);
+#endif
+}
+
+static int crVBoxHGSMISetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
+{
+    CRVBOXHGCMSETVERSION parms;
+    int rc;
+
+    parms.hdr.result      = VERR_WRONG_ORDER;
+    parms.hdr.u32ClientID = conn->u32ClientID;
+    parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_VERSION;
+    parms.hdr.cParms      = SHCRGL_CPARMS_SET_VERSION;
+
+    parms.vMajor.type      = VMMDevHGCMParmType_32bit;
+    parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
+    parms.vMinor.type      = VMMDevHGCMParmType_32bit;
+    parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
+
+    rc = crVBoxHGCMCall(&parms, sizeof(parms));
+
+    if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
+    {
+        crWarning("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
+                  parms.vMajor.u.value32, parms.vMinor.u.value32);
+        return FALSE;
+    }
+
+    conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
+    conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
+
+    return TRUE;
+}
+
+/**
+ * The function that actually connects.  This should only be called by clients,
+ * guests in vbox case.
+ * Servers go through crVBoxHGCMAccept;
+ */
+/*@todo use vbglR3Something here */
+static int crVBoxHGSMIDoConnect( CRConnection *conn )
+{
+#ifdef IN_GUEST
+    VBoxGuestHGCMConnectInfo info;
+
+#ifdef RT_OS_WINDOWS
+    DWORD cbReturned;
+
+    if (g_crvboxhgsmi.hGuestDrv == INVALID_HANDLE_VALUE)
+    {
+        /* open VBox guest driver */
+        g_crvboxhgsmi.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
+                                        GENERIC_READ | GENERIC_WRITE,
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                        NULL,
+                                        OPEN_EXISTING,
+                                        FILE_ATTRIBUTE_NORMAL,
+                                        NULL);
+
+        /* @todo check if we could rollback to softwareopengl */
+        if (g_crvboxhgsmi.hGuestDrv == INVALID_HANDLE_VALUE)
+        {
+            crDebug("could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
+            return FALSE;
+        }
+    }
+#else
+    if (g_crvboxhgsmi.iGuestDrv == INVALID_HANDLE_VALUE)
+    {
+        g_crvboxhgsmi.iGuestDrv = open(VBOXGUEST_USER_DEVICE_NAME, O_RDWR, 0);
+        if (g_crvboxhgsmi.iGuestDrv == INVALID_HANDLE_VALUE)
+        {
+            crDebug("could not open Guest Additions kernel module! rc = %d\n", errno);
+            return FALSE;
+        }
+    }
+#endif
+
+    memset (&info, 0, sizeof (info));
+    info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
+    strcpy (info.Loc.u.host.achName, "VBoxSharedCrOpenGL");
+
+#ifdef RT_OS_WINDOWS
+    if (DeviceIoControl(g_crvboxhgsmi.hGuestDrv,
+                        VBOXGUEST_IOCTL_HGCM_CONNECT,
+                        &info, sizeof (info),
+                        &info, sizeof (info),
+                        &cbReturned,
+                        NULL))
+#elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+    VBGLBIGREQ Hdr;
+    Hdr.u32Magic = VBGLBIGREQ_MAGIC;
+    Hdr.cbData = sizeof(info);
+    Hdr.pvDataR3 = &info;
+# if HC_ARCH_BITS == 32
+    Hdr.u32Padding = 0;
+# endif
+    if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &Hdr) >= 0)
+#else
+    /*@todo it'd fail */
+    if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info)) >= 0)
+#endif
+    {
+        if (info.result == VINF_SUCCESS)
+        {
+            conn->u32ClientID = info.u32ClientID;
+            crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
+
+            return crVBoxHGSMISetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
+        }
+        else
+        {
+            crDebug("HGCM connect failed with rc=0x%x\n", info.result);
+        }
+    }
+    else
+    {
+#ifdef RT_OS_WINDOWS
+        crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", GetLastError());
+#else
+        crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", errno);
+#endif
+    }
+
+    return FALSE;
+#else /*#ifdef IN_GUEST*/
+    crError("crVBoxHGSMIDoConnect called on host side!");
+    CRASSERT(FALSE);
+    return FALSE;
+#endif
+}
+
+/*@todo same, replace DeviceIoControl with vbglR3DoIOCtl */
+static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
+{
+#ifdef IN_GUEST
+    VBoxGuestHGCMDisconnectInfo info;
+# ifdef RT_OS_WINDOWS
+    DWORD cbReturned;
+# endif
+    int i;
+#endif
+
+    if (conn->pHostBuffer)
+    {
+        crFree(conn->pHostBuffer);
+        conn->pHostBuffer = NULL;
+        conn->cbHostBuffer = 0;
+        conn->cbHostBufferAllocated = 0;
+    }
+
+    conn->pBuffer = NULL;
+    conn->cbBuffer = 0;
+
+    //@todo hold lock here?
+    if (conn->type == CR_VBOXHGCM)
+    {
+        --g_crvboxhgsmi.num_conns;
+
+        if (conn->index < g_crvboxhgsmi.num_conns)
+        {
+            g_crvboxhgsmi.conns[conn->index] = g_crvboxhgsmi.conns[g_crvboxhgsmi.num_conns];
+            g_crvboxhgsmi.conns[conn->index]->index = conn->index;
+        }
+        else g_crvboxhgsmi.conns[conn->index] = NULL;
+
+        conn->type = CR_NO_CONNECTION;
+    }
+
+#ifndef IN_GUEST
+#else /* IN_GUEST */
+    if (conn->u32ClientID)
+    {
+        memset (&info, 0, sizeof (info));
+        info.u32ClientID = conn->u32ClientID;
+
+# ifdef RT_OS_WINDOWS
+        if ( !DeviceIoControl(g_crvboxhgsmi.hGuestDrv,
+                               VBOXGUEST_IOCTL_HGCM_DISCONNECT,
+                               &info, sizeof (info),
+                               &info, sizeof (info),
+                               &cbReturned,
+                               NULL) )
+        {
+            crDebug("Disconnect failed with %x\n", GetLastError());
+        }
+# elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+        VBGLBIGREQ Hdr;
+        Hdr.u32Magic = VBGLBIGREQ_MAGIC;
+        Hdr.cbData = sizeof(info);
+        Hdr.pvDataR3 = &info;
+#  if HC_ARCH_BITS == 32
+        Hdr.u32Padding = 0;
+#  endif
+        if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Hdr) >= 0)
+# else
+        if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info, sizeof (info)) < 0)
+        {
+            crDebug("Disconnect failed with %x\n", errno);
+        }
+# endif
+
+        conn->u32ClientID = 0;
+    }
+
+    /* see if any connections remain */
+    for (i = 0; i < g_crvboxhgsmi.num_conns; i++)
+        if (g_crvboxhgsmi.conns[i] && g_crvboxhgsmi.conns[i]->type != CR_NO_CONNECTION)
+            break;
+
+    /* close guest additions driver*/
+    if (i>=g_crvboxhgsmi.num_conns)
+    {
+# ifdef RT_OS_WINDOWS
+        CloseHandle(g_crvboxhgsmi.hGuestDrv);
+        g_crvboxhgsmi.hGuestDrv = INVALID_HANDLE_VALUE;
+# else
+        close(g_crvboxhgsmi.iGuestDrv);
+        g_crvboxhgsmi.iGuestDrv = INVALID_HANDLE_VALUE;
+# endif
+    }
+#endif /* IN_GUEST */
+}
+
+static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
+{
+    crVBoxHGSMIFree(conn, mess);
+    CRASSERT(FALSE);
+}
+
+static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
+{
+    CRASSERT(FALSE);
+}
+
+DECLCALLBACK(HVBOXCRHGSMI_CLIENT) _crVBoxHGSMIClientCreate(PVBOXUHGSMI pHgsmi)
+{
+    PCRVBOXHGSMI_CLIENT pClient = crAlloc(sizeof (CRVBOXHGSMI_CLIENT));
+    if (pClient)
+    {
+        int rc;
+        pClient->pHgsmi = pHgsmi;
+        rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1),
+                                VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE, NULL,
+                                &pClient->pCmdBuffer);
+        if (RT_SUCCESS(rc))
+        {
+            rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(0x800000),
+                                            VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE, NULL,
+                                            &pClient->pHGBuffer);
+            if (RT_SUCCESS(rc))
+            {
+                pClient->pvHGBuffer = NULL;
+                pClient->bufpool = crBufferPoolInit(16);
+                return (HVBOXCRHGSMI_CLIENT) pClient;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+DECLCALLBACK(void) _crVBoxHGSMIClientDestroy(HVBOXCRHGSMI_CLIENT hClient)
+{
+    /* @todo */
+}
+
+
+bool crVBoxHGSMIInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
+{
+    /* static */ int bHasHGSMI = -1; /* <- do it for each connection */
+    (void) mtu;
+
+    if (bHasHGSMI < 0)
+    {
+        int rc;
+        VBOXCRHGSMI_CALLBACKS Callbacks;
+        Callbacks.pfnClientCreate = _crVBoxHGSMIClientCreate;
+        Callbacks.pfnClientDestroy = _crVBoxHGSMIClientDestroy;
+        rc = VBoxCrHgsmiInit(&Callbacks);
+        if (RT_SUCCESS(rc))
+            bHasHGSMI = 1;
+        else
+            bHasHGSMI = 0;
+    }
+
+    if (!bHasHGSMI)
+        return false;
+
+    g_crvboxhgsmi.recv_list = rfl;
+    g_crvboxhgsmi.close_list = cfl;
+    if (g_crvboxhgsmi.initialized)
+    {
+        return true;
+    }
+
+    g_crvboxhgsmi.initialized = 1;
+
+    g_crvboxhgsmi.num_conns = 0;
+    g_crvboxhgsmi.conns     = NULL;
+    g_crvboxhgsmi.mempool = crBufferPoolInit(16);
+
+    /* Can't open VBox guest driver here, because it gets called for host side as well */
+    /*@todo as we have 2 dll versions, can do it now.*/
+
+
+#ifdef CHROMIUM_THREADSAFE
+    crInitMutex(&g_crvboxhgsmi.mutex);
+    crInitMutex(&g_crvboxhgsmi.recvmutex);
+#endif
+
+    return true;
+}
+
+/* Callback function used to free buffer pool entries */
+void _crVBoxHGSMISysMemFree(void *data)
+{
+    crFree(data);
+}
+
+void crVBoxHGSMITearDown(void)
+{
+    int32_t i, cCons;
+
+    if (!g_crvboxhgsmi.initialized) return;
+
+    /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
+     * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
+     * order of their connection.
+     */
+    cCons = g_crvboxhgsmi.num_conns;
+    for (i=0; i<cCons; i++)
+    {
+        /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
+        crNetDisconnect(g_crvboxhgsmi.conns[0]);
+    }
+    CRASSERT(0==g_crvboxhgsmi.num_conns);
+
+#ifdef CHROMIUM_THREADSAFE
+    crFreeMutex(&g_crvboxhgsmi.mutex);
+    crFreeMutex(&g_crvboxhgsmi.recvmutex);
+#endif
+
+    if (g_crvboxhgsmi.mempool)
+        crBufferPoolCallbackFree(g_crvboxhgsmi.mempool, _crVBoxHGSMISysMemFree);
+    g_crvboxhgsmi.mempool = NULL;
+
+    g_crvboxhgsmi.initialized = 0;
+
+    crFree(g_crvboxhgsmi.conns);
+    g_crvboxhgsmi.conns = NULL;
+}
+
+void crVBoxHGSMIConnection(CRConnection *conn)
+{
+    int i, found = 0;
+    int n_bytes;
+
+    CRASSERT(g_crvboxhgsmi.initialized);
+
+    conn->type = CR_VBOXHGCM;
+    conn->Alloc = crVBoxHGSMIAlloc;
+    conn->Send = crVBoxHGSMISend;
+    conn->SendExact = crVBoxHGSMIWriteExact;
+    conn->Recv = crVBoxHGSMISingleRecv;
+    conn->RecvMsg = crVBoxHGSMIReceiveMessage;
+    conn->Free = crVBoxHGSMIFree;
+    conn->Accept = crVBoxHGSMIAccept;
+    conn->Connect = crVBoxHGSMIDoConnect;
+    conn->Disconnect = crVBoxHGSMIDoDisconnect;
+    conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
+    conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
+    conn->index = g_crvboxhgsmi.num_conns;
+    conn->sizeof_buffer_header = sizeof(CRVBOXHGSMIBUFFER);
+    conn->actual_network = 1;
+
+    conn->krecv_buf_size = 0;
+
+    conn->pBuffer = NULL;
+    conn->cbBuffer = 0;
+    conn->allow_redir_ptr = 1;
+
+    //@todo remove this crap at all later
+    conn->cbHostBufferAllocated = 0;//2*1024;
+    conn->pHostBuffer = NULL;//(uint8_t*) crAlloc(conn->cbHostBufferAllocated);
+//    CRASSERT(conn->pHostBuffer);
+    conn->cbHostBuffer = 0;
+
+    /* Find a free slot */
+    for (i = 0; i < g_crvboxhgsmi.num_conns; i++) {
+        if (g_crvboxhgsmi.conns[i] == NULL) {
+            conn->index = i;
+            g_crvboxhgsmi.conns[i] = conn;
+            found = 1;
+            break;
+        }
+    }
+
+    /* Realloc connection stack if we couldn't find a free slot */
+    if (found == 0) {
+        n_bytes = ( g_crvboxhgsmi.num_conns + 1 ) * sizeof(*g_crvboxhgsmi.conns);
+        crRealloc( (void **) &g_crvboxhgsmi.conns, n_bytes );
+        g_crvboxhgsmi.conns[g_crvboxhgsmi.num_conns++] = conn;
+    }
+}
+
+int crVBoxHGSMIRecv(void)
+{
+    int32_t i;
+
+#ifdef IN_GUEST
+    /* we're on guest side, poll host if it got something for us */
+    for (i=0; i<g_crvboxhgsmi.num_conns; i++)
+    {
+        CRConnection *conn = g_crvboxhgsmi.conns[i];
+
+        if ( !conn || conn->type == CR_NO_CONNECTION )
+            continue;
+
+        if (!conn->pBuffer)
+        {
+            PCRVBOXHGSMI_CLIENT pClient = _crVBoxHGSMIClientGet();
+            _crVBoxHGSMIPollHost(conn, pClient);
+        }
+    }
+#endif
+
+    for (i=0; i<g_crvboxhgsmi.num_conns; i++)
+    {
+        CRConnection *conn = g_crvboxhgsmi.conns[i];
+
+        if ( !conn || conn->type == CR_NO_CONNECTION )
+            continue;
+
+        if (conn->cbBuffer>0)
+        {
+            PCRVBOXHGSMI_CLIENT pClient = _crVBoxHGSMIClientGet();
+            _crVBoxHGSMIReceiveMessage(conn, pClient);
+        }
+    }
+
+    return 0;
+}
+
+CRConnection** crVBoxHGSMIDump( int *num )
+{
+    *num = g_crvboxhgsmi.num_conns;
+
+    return g_crvboxhgsmi.conns;
+}
+#endif /* #ifdef IN_GUEST */
