VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c @ 69989

Revision 69989, 70.7 KB checked in by vboxsync, 5 weeks ago (diff)

Additions/common/OpenGL: fix regressions from r117617/public r68472.
bugref:9060: vboxvideo: hanging login screen starting Ubuntu 17.10 guest with 3D
r117617/public r68472 and the follow-up switched from using duplicate code in
the X11 libGL code to access the guest driver and HGCM to using the common
code. It contained at least two problems: it failed to initialise the
runtime library before calling into the Guest library and it changed error
checking semantics slightly, causing us to fail to handle a too-small-buffer
error and sending GNOME Shell into an endless loop. This change fixes that
and also adds todo comments to other places where the error handling should
be cleaned up, but which I do not want to change and test just now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* $Id$ */
2/** @file
3 * VBox HGCM connection
4 */
5
6/*
7 * Copyright (C) 2008-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef RT_OS_WINDOWS
19# include <iprt/win/windows.h>
20# include <ddraw.h>
21#else
22# include <sys/ioctl.h>
23# include <errno.h>
24# include <fcntl.h>
25# include <string.h>
26# include <unistd.h>
27#endif
28
29#include "cr_error.h"
30#include "cr_net.h"
31#include "cr_bufpool.h"
32#include "cr_mem.h"
33#include "cr_string.h"
34#include "cr_endian.h"
35#include "cr_threads.h"
36#include "net_internals.h"
37#include "cr_process.h"
38
39#include <iprt/initterm.h>
40#include <iprt/thread.h>
41
42#include <VBox/VBoxGuestLib.h>
43#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
44
45#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
46#include <VBoxCrHgsmi.h>
47#endif
48
49/** @todo move define somewhere else, and make sure it's less than VBGLR0_MAX_HGCM_KERNEL_PARM*/
50/*If we fail to pass data in one chunk, send it in chunks of this size instead*/
51#define CR_HGCM_SPLIT_BUFFER_SIZE (8*_1M)
52
53#ifndef MIN
54# define MIN(a, b) ((a) < (b) ? (a) : (b))
55#endif
56
57#ifdef DEBUG_misha
58#ifdef CRASSERT
59# undef CRASSERT
60#endif
61#define CRASSERT Assert
62#endif
63/*#define IN_GUEST
64#if defined(IN_GUEST)
65#define VBOX_WITH_CRHGSMIPROFILE
66#endif */
67#ifdef VBOX_WITH_CRHGSMIPROFILE
68#include <iprt/time.h>
69#include <stdio.h>
70
71typedef struct VBOXCRHGSMIPROFILE
72{
73    uint64_t cStartTime;
74    uint64_t cStepsTime;
75    uint64_t cSteps;
76} VBOXCRHGSMIPROFILE, *PVBOXCRHGSMIPROFILE;
77
78#define VBOXCRHGSMIPROFILE_GET_TIME_NANO() RTTimeNanoTS()
79#define VBOXCRHGSMIPROFILE_GET_TIME_MILLI() RTTimeMilliTS()
80
81/* 10 sec */
82#define VBOXCRHGSMIPROFILE_LOG_STEP_TIME (10000000000.)
83
84DECLINLINE(void) vboxCrHgsmiProfileStart(PVBOXCRHGSMIPROFILE pProfile)
85{
86    pProfile->cStepsTime = 0;
87    pProfile->cSteps = 0;
88    pProfile->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
89}
90
91DECLINLINE(void) vboxCrHgsmiProfileStep(PVBOXCRHGSMIPROFILE pProfile, uint64_t cStepTime)
92{
93    pProfile->cStepsTime += cStepTime;
94    ++pProfile->cSteps;
95}
96
97typedef struct VBOXCRHGSMIPROFILE_SCOPE
98{
99    uint64_t cStartTime;
100/*    bool bDisable;*/
101} VBOXCRHGSMIPROFILE_SCOPE, *PVBOXCRHGSMIPROFILE_SCOPE;
102
103static VBOXCRHGSMIPROFILE g_VBoxProfile;
104
105static void vboxCrHgsmiLog(char * szString, ...)
106{
107    char szBuffer[4096] = {0};
108     va_list pArgList;
109     va_start(pArgList, szString);
110     _vsnprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szString, pArgList);
111     va_end(pArgList);
112
113#ifdef VBOX_WITH_CRHGSMI
114     VBoxCrHgsmiLog(szBuffer);
115#else
116     OutputDebugString(szBuffer);
117#endif
118}
119
120DECLINLINE(void) vboxCrHgsmiProfileLog(PVBOXCRHGSMIPROFILE pProfile, uint64_t cTime)
121{
122    uint64_t profileTime = cTime - pProfile->cStartTime;
123    double percent = ((double)100.0) * pProfile->cStepsTime / profileTime;
124    double cps = ((double)1000000000.) * pProfile->cSteps / profileTime;
125    vboxCrHgsmiLog("hgcm: cps: %.1f, host %.1f%%\n", cps, percent);
126}
127
128DECLINLINE(void) vboxCrHgsmiProfileScopeEnter(PVBOXCRHGSMIPROFILE_SCOPE pScope)
129{
130/*    pScope->bDisable = false; */
131    pScope->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
132}
133
134DECLINLINE(void) vboxCrHgsmiProfileScopeExit(PVBOXCRHGSMIPROFILE_SCOPE pScope)
135{
136/*    if (!pScope->bDisable) */
137    {
138        uint64_t cTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
139        vboxCrHgsmiProfileStep(&g_VBoxProfile, cTime - pScope->cStartTime);
140        if (VBOXCRHGSMIPROFILE_LOG_STEP_TIME < cTime - g_VBoxProfile.cStartTime)
141        {
142            vboxCrHgsmiProfileLog(&g_VBoxProfile, cTime);
143            vboxCrHgsmiProfileStart(&g_VBoxProfile);
144        }
145    }
146}
147
148
149#define VBOXCRHGSMIPROFILE_INIT() vboxCrHgsmiProfileStart(&g_VBoxProfile)
150#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
151
152#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() \
153        VBOXCRHGSMIPROFILE_SCOPE __vboxCrHgsmiProfileScope; \
154        vboxCrHgsmiProfileScopeEnter(&__vboxCrHgsmiProfileScope);
155
156#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() \
157        vboxCrHgsmiProfileScopeExit(&__vboxCrHgsmiProfileScope); \
158
159
160#else
161#define VBOXCRHGSMIPROFILE_INIT() do {} while (0)
162#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
163#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() do {} while (0)
164#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() do {} while (0)
165#endif
166
167typedef struct {
168    int                  initialized;
169    int                  num_conns;
170    CRConnection         **conns;
171    CRBufferPool         *bufpool;
172#ifdef CHROMIUM_THREADSAFE
173    CRmutex              mutex;
174    CRmutex              recvmutex;
175#endif
176    CRNetReceiveFuncList *recv_list;
177    CRNetCloseFuncList   *close_list;
178#ifdef RT_OS_WINDOWS
179    LPDIRECTDRAW         pDirectDraw;
180#endif
181#ifdef IN_GUEST
182    uint32_t             u32HostCaps;
183    bool                 fHostCapsInitialized;
184#endif
185#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
186    bool bHgsmiOn;
187#endif
188} CRVBOXHGCMDATA;
189
190static CRVBOXHGCMDATA g_crvboxhgcm = {0,};
191
192typedef enum {
193    CR_VBOXHGCM_USERALLOCATED,
194    CR_VBOXHGCM_MEMORY,
195    CR_VBOXHGCM_MEMORY_BIG
196#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
197    ,CR_VBOXHGCM_UHGSMI_BUFFER
198#endif
199} CRVBOXHGCMBUFFERKIND;
200
201#define CR_VBOXHGCM_BUFFER_MAGIC 0xABCDE321
202
203typedef struct CRVBOXHGCMBUFFER {
204    uint32_t             magic;
205    CRVBOXHGCMBUFFERKIND kind;
206    union
207    {
208        struct
209        {
210            uint32_t             len;
211            uint32_t             allocated;
212        };
213
214#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
215        PVBOXUHGSMI_BUFFER pBuffer;
216#endif
217    };
218} CRVBOXHGCMBUFFER;
219
220#ifndef RT_OS_WINDOWS
221    #define TRUE true
222    #define FALSE false
223    #define INVALID_HANDLE_VALUE (-1)
224#endif
225
226
227#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
228
229/* add sizeof header + page align */
230#define CRVBOXHGSMI_PAGE_ALIGN(_s) (((_s)  + 0xfff) & ~0xfff)
231#define CRVBOXHGSMI_BUF_HDR_SIZE() (sizeof (CRVBOXHGCMBUFFER))
232#define CRVBOXHGSMI_BUF_SIZE(_s) CRVBOXHGSMI_PAGE_ALIGN((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
233#define CRVBOXHGSMI_BUF_LOCK_SIZE(_s) ((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
234#define CRVBOXHGSMI_BUF_DATA(_p) ((void*)(((CRVBOXHGCMBUFFER*)(_p)) + 1))
235#define CRVBOXHGSMI_BUF_HDR(_p) (((CRVBOXHGCMBUFFER*)(_p)) - 1)
236#define CRVBOXHGSMI_BUF_OFFSET(_st2, _st1) ((uint32_t)(((uint8_t*)(_st2)) - ((uint8_t*)(_st1))))
237
238static int _crVBoxHGSMIClientInit(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI pHgsmi)
239{
240    int rc;
241    VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
242    pClient->pHgsmi = pHgsmi;
243    Flags.fCommand = 1;
244    rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1), Flags, &pClient->pCmdBuffer);
245    if (RT_SUCCESS(rc))
246    {
247        Flags.Value = 0;
248        rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1), Flags, &pClient->pHGBuffer);
249        if (RT_SUCCESS(rc))
250        {
251            pClient->pvHGBuffer = NULL;
252            pClient->bufpool = crBufferPoolInit(16);
253            return VINF_SUCCESS;
254        }
255        else
256            crWarning("_crVBoxHGSMIClientInit: pfnBufferCreate failed to allocate host->guest buffer");
257
258        pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
259    }
260    else
261        crWarning("_crVBoxHGSMIClientInit: pfnBufferCreate failed to allocate cmd buffer");
262
263    pClient->pHgsmi = NULL;
264    return rc;
265}
266
267void _crVBoxHGSMIBufferFree(void *data)
268{
269    PVBOXUHGSMI_BUFFER pBuffer = (PVBOXUHGSMI_BUFFER)data;
270    pBuffer->pfnDestroy(pBuffer);
271}
272
273static int _crVBoxHGSMIClientTerm(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI *ppHgsmi)
274{
275    if (pClient->bufpool)
276        crBufferPoolCallbackFree(pClient->bufpool, _crVBoxHGSMIBufferFree);
277    pClient->bufpool = NULL;
278
279    if (pClient->pHGBuffer)
280    {
281        pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
282        pClient->pHGBuffer = NULL;
283    }
284
285    if (pClient->pCmdBuffer)
286    {
287        pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
288        pClient->pCmdBuffer = NULL;
289    }
290
291    if (ppHgsmi)
292    {
293        *ppHgsmi = pClient->pHgsmi;
294    }
295    pClient->pHgsmi = NULL;
296
297    return VINF_SUCCESS;
298}
299
300
301#ifdef VBOX_CRHGSMI_WITH_D3DDEV
302
303static DECLCALLBACK(HVBOXCRHGSMI_CLIENT) _crVBoxHGSMIClientCreate(PVBOXUHGSMI pHgsmi)
304{
305    PCRVBOXHGSMI_CLIENT pClient = crAlloc(sizeof (CRVBOXHGSMI_CLIENT));
306
307    if (pClient)
308    {
309        int rc = _crVBoxHGSMIClientInit(pClient, pHgsmi);
310        if (RT_SUCCESS(rc))
311            return (HVBOXCRHGSMI_CLIENT)pClient;
312        else
313            crWarning("_crVBoxHGSMIClientCreate: _crVBoxHGSMIClientInit failed rc %d", rc);
314
315        crFree(pCLient);
316    }
317
318    return NULL;
319}
320
321static DECLCALLBACK(void) _crVBoxHGSMIClientDestroy(HVBOXCRHGSMI_CLIENT hClient)
322{
323    PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)hClient;
324    _crVBoxHGSMIClientTerm(pClient, NULL);
325    crFree(pClient);
326}
327#endif
328
329DECLINLINE(PCRVBOXHGSMI_CLIENT) _crVBoxHGSMIClientGet(CRConnection *conn)
330{
331#ifdef VBOX_CRHGSMI_WITH_D3DDEV
332    PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)VBoxCrHgsmiQueryClient();
333    CRASSERT(pClient);
334    return pClient;
335#else
336    if (conn->HgsmiClient.pHgsmi)
337        return &conn->HgsmiClient;
338    {
339        PVBOXUHGSMI pHgsmi = conn->pExternalHgsmi ? conn->pExternalHgsmi : VBoxCrHgsmiCreate();
340        if (pHgsmi)
341        {
342            int rc = _crVBoxHGSMIClientInit(&conn->HgsmiClient, pHgsmi);
343            if (RT_SUCCESS(rc))
344            {
345                CRASSERT(conn->HgsmiClient.pHgsmi);
346                return &conn->HgsmiClient;
347            }
348            else
349                crWarning("_crVBoxHGSMIClientGet: _crVBoxHGSMIClientInit failed rc %d", rc);
350            if (!conn->pExternalHgsmi)
351                VBoxCrHgsmiDestroy(pHgsmi);
352        }
353        else
354        {
355            crWarning("VBoxCrHgsmiCreate failed");
356        }
357    }
358    return NULL;
359#endif
360}
361
362static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
363{
364    PVBOXUHGSMI_BUFFER buf;
365    int rc;
366
367    buf = (PVBOXUHGSMI_BUFFER ) crBufferPoolPop(pClient->bufpool, cbSize);
368
369    if (!buf)
370    {
371        VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
372        crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
373                        (void *) pClient->bufpool,
374                        cbSize);
375        rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, cbSize, Flags, &buf);
376        if (RT_FAILURE(rc))
377            crWarning("_crVBoxHGSMIBufAlloc: Failed to Create a buffer of size(%d), rc(%d)\n", cbSize, rc);
378    }
379    return buf;
380}
381
382static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufFromHdr(CRVBOXHGCMBUFFER *pHdr)
383{
384    PVBOXUHGSMI_BUFFER pBuf;
385    int rc;
386    CRASSERT(pHdr->magic == CR_VBOXHGCM_BUFFER_MAGIC);
387    CRASSERT(pHdr->kind == CR_VBOXHGCM_UHGSMI_BUFFER);
388    pBuf = pHdr->pBuffer;
389    rc = pBuf->pfnUnlock(pBuf);
390    if (RT_FAILURE(rc))
391    {
392        crWarning("_crVBoxHGSMIBufFromHdr: pfnUnlock failed rc %d", rc);
393        return NULL;
394    }
395    return pBuf;
396}
397
398static void _crVBoxHGSMIBufFree(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf)
399{
400    crBufferPoolPush(pClient->bufpool, pBuf, pBuf->cbBuffer);
401}
402
403static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLock(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
404{
405    /* in theory it is OK to use one cmd buffer for asynch cmd submission
406     * because bDiscard flag should result in allocating a new memory backend if the
407     * allocation is still in use.
408     * However, NOTE: since one and the same semaphore synch event is used for completion notification,
409     * for the notification mechanism working as expected
410     * 1. host must complete commands in the same order as it receives them
411     * (to avoid situation when guest receives notification for another command completion)
412     * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
413     * 3. guest must wait for command completion in the same order as it submits them
414     * in case we can not satisfy any of the above, we should introduce multiple command buffers */
415    CRVBOXHGSMIHDR * pHdr;
416    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
417    int rc;
418    fFlags.Value = 0;
419    fFlags.bDiscard = 1;
420    rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
421    if (RT_SUCCESS(rc))
422        return pHdr;
423    else
424        crWarning("_crVBoxHGSMICmdBufferLock: pfnLock failed rc %d", rc);
425
426    crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
427    return NULL;
428}
429
430static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLockRo(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
431{
432    /* in theory it is OK to use one cmd buffer for asynch cmd submission
433     * because bDiscard flag should result in allocating a new memory backend if the
434     * allocation is still in use.
435     * However, NOTE: since one and the same semaphore synch event is used for completion notification,
436     * for the notification mechanism working as expected
437     * 1. host must complete commands in the same order as it receives them
438     * (to avoid situation when guest receives notification for another command completion)
439     * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
440     * 3. guest must wait for command completion in the same order as it submits them
441     * in case we can not satisfy any of the above, we should introduce multiple command buffers */
442    CRVBOXHGSMIHDR * pHdr = NULL;
443    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
444    int rc;
445    fFlags.Value = 0;
446    fFlags.bReadOnly = 1;
447    rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
448    if (RT_FAILURE(rc))
449        crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
450    return pHdr;
451}
452
453static void _crVBoxHGSMICmdBufferUnlock(PCRVBOXHGSMI_CLIENT pClient)
454{
455    int rc = pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
456    if (RT_FAILURE(rc))
457        crError("Failed to Unlock the command buffer rc(%d)\n", rc);
458}
459
460static int32_t _crVBoxHGSMICmdBufferGetRc(PCRVBOXHGSMI_CLIENT pClient)
461{
462    CRVBOXHGSMIHDR * pHdr;
463    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
464    int rc;
465
466    fFlags.Value = 0;
467    fFlags.bReadOnly = 1;
468    rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, sizeof (*pHdr), fFlags, (void**)&pHdr);
469    if (RT_FAILURE(rc))
470    {
471        crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", sizeof (*pHdr), rc);
472        return rc;
473    }
474
475    rc = pHdr->result;
476    AssertRC(rc);
477    pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
478
479    return rc;
480}
481
482DECLINLINE(PVBOXUHGSMI_BUFFER) _crVBoxHGSMIRecvBufGet(PCRVBOXHGSMI_CLIENT pClient)
483{
484    if (pClient->pvHGBuffer)
485    {
486        int rc = pClient->pHGBuffer->pfnUnlock(pClient->pHGBuffer);
487        if (RT_FAILURE(rc))
488        {
489            return NULL;
490        }
491        pClient->pvHGBuffer = NULL;
492    }
493    return pClient->pHGBuffer;
494}
495
496DECLINLINE(void*) _crVBoxHGSMIRecvBufData(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
497{
498    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
499    int rc;
500    CRASSERT(!pClient->pvHGBuffer);
501    fFlags.Value = 0;
502    rc = pClient->pHGBuffer->pfnLock(pClient->pHGBuffer, 0, cbBuffer, fFlags, &pClient->pvHGBuffer);
503    if (RT_SUCCESS(rc))
504        return pClient->pvHGBuffer;
505    else
506        crWarning("_crVBoxHGSMIRecvBufData: pfnLock failed rc %d", rc);
507
508    return NULL;
509}
510
511DECLINLINE(void) _crVBoxHGSMIFillCmd(VBOXUHGSMI_BUFFER_SUBMIT *pSubm, PCRVBOXHGSMI_CLIENT pClient, uint32_t cbData)
512{
513    pSubm->pBuf = pClient->pCmdBuffer;
514    pSubm->offData = 0;
515    pSubm->cbData = cbData;
516    pSubm->fFlags.Value = 0;
517    pSubm->fFlags.bDoNotRetire = 1;
518# if 0
519    pSubm->fFlags.bDoNotSignalCompletion = 1; /* <- we do not need that actually since
520                                               * in case we want completion,
521                                               * we will block in _crVBoxHGSMICmdBufferGetRc (when locking the buffer)
522                                               * which is needed for getting the result */
523# endif
524}
525#endif
526
527/* Some forward declarations */
528static void _crVBoxHGCMReceiveMessage(CRConnection *conn);
529
530#ifndef IN_GUEST
531static bool _crVBoxHGCMReadBytes(CRConnection *conn, void *buf, uint32_t len)
532{
533    CRASSERT(conn && buf);
534
535    if (!conn->pBuffer || (conn->cbBuffer<len))
536        return FALSE;
537
538    crMemcpy(buf, conn->pBuffer, len);
539
540    conn->cbBuffer -= len;
541    conn->pBuffer = conn->cbBuffer>0 ? (uint8_t*)conn->pBuffer+len : NULL;
542
543    return TRUE;
544}
545#endif
546
547#ifndef IN_GUEST
548/** @todo get rid of it*/
549static bool _crVBoxHGCMWriteBytes(CRConnection *conn, const void *buf, uint32_t len)
550{
551    CRASSERT(conn && buf);
552
553    /* make sure there's host buffer and it's clear */
554    CRASSERT(conn->pHostBuffer && !conn->cbHostBuffer);
555
556    if (conn->cbHostBufferAllocated < len)
557    {
558        crDebug("Host buffer too small %d out of requested %d bytes, reallocating", conn->cbHostBufferAllocated, len);
559        crFree(conn->pHostBuffer);
560        conn->pHostBuffer = crAlloc(len);
561        if (!conn->pHostBuffer)
562        {
563            conn->cbHostBufferAllocated = 0;
564            crError("OUT_OF_MEMORY trying to allocate %d bytes", len);
565            return FALSE;
566        }
567        conn->cbHostBufferAllocated = len;
568    }
569
570    crMemcpy(conn->pHostBuffer, buf, len);
571    conn->cbHostBuffer = len;
572
573    return TRUE;
574}
575#endif
576
577/**
578 * Send an HGCM request
579 *
580 * @return VBox status code
581 * @param   pvData      Data pointer
582 * @param   cbData      Data size
583 */
584static int crVBoxHGCMCall(CRConnection *conn, PVBGLIOCHGCMCALL pData, unsigned cbData)
585{
586#ifdef IN_GUEST
587    int rc;
588# ifndef VBOX_WITH_CRHGSMI
589    RT_NOREF(conn);
590# else
591    PCRVBOXHGSMI_CLIENT pClient = g_crvboxhgcm.bHgsmiOn ? _crVBoxHGSMIClientGet(conn) : NULL;
592    if (pClient)
593        rc = VBoxCrHgsmiCtlConCall(pClient->pHgsmi, pData, cbData);
594    else
595# endif
596    {
597        rc = VbglR3HGCMCall(pData, cbData);
598        if (RT_SUCCESS(rc))
599        { /* likely */ }
600        else
601        {
602            crWarning("vboxCall failed with VBox status code %Rrc\n", rc);
603# ifndef RT_OS_WINDOWS
604            if (rc == VERR_INTERRUPTED)
605            {
606                /* Not sure why we're doing the sleep stuff here.  The original coder didn't
607                   bother to mention why he thought it necessary.  :-( */
608                RTMSINTERVAL msSleep;
609                int i;
610                for (i = 0, msSleep = 50; i < 6; i++, msSleep = msSleep * 2)
611                {
612                    RTThreadSleep(msSleep);
613                    rc = VbglR3HGCMCall(pData, cbData);
614                    if (rc != VERR_INTERRUPTED)
615                    {
616                        if (RT_SUCCESS(rc))
617                            crWarning("vboxCall retry(%i) succeeded", i + 1);
618                        else
619                            crWarning("vboxCall retry(%i) failed with VBox status code %Rrc", i + 1, rc);
620                        break;
621                    }
622                }
623            }
624#  endif
625        }
626    }
627    return rc;
628
629#else  /* IN_GUEST */
630    RT_NOREF(conn, pData, cbData);
631    crError("crVBoxHGCMCall called on host side!");
632    CRASSERT(FALSE);
633    return VERR_NOT_SUPPORTED;
634#endif /* IN_GUEST */
635}
636
637static void *_crVBoxHGCMAlloc(CRConnection *conn)
638{
639    CRVBOXHGCMBUFFER *buf;
640
641#ifdef CHROMIUM_THREADSAFE
642    crLockMutex(&g_crvboxhgcm.mutex);
643#endif
644
645    buf = (CRVBOXHGCMBUFFER *) crBufferPoolPop(g_crvboxhgcm.bufpool, conn->buffer_size);
646
647    if (!buf)
648    {
649        crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
650                        (void *) g_crvboxhgcm.bufpool,
651                        (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
652
653        /* We're either on host side, or we failed to allocate DDRAW buffer */
654        if (!buf)
655        {
656            crDebug("Using system malloc\n");
657            buf = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size );
658            CRASSERT(buf);
659            buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
660            buf->kind  = CR_VBOXHGCM_MEMORY;
661            buf->allocated = conn->buffer_size;
662        }
663    }
664
665#ifdef CHROMIUM_THREADSAFE
666    crUnlockMutex(&g_crvboxhgcm.mutex);
667#endif
668
669    return (void *)( buf + 1 );
670
671}
672
673static void *crVBoxHGCMAlloc(CRConnection *conn)
674{
675    void *pvBuff;
676    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
677#ifdef CHROMIUM_THREADSAFE
678    crLockMutex(&g_crvboxhgcm.mutex);
679#endif
680    pvBuff = _crVBoxHGCMAlloc(conn);
681#ifdef CHROMIUM_THREADSAFE
682    crUnlockMutex(&g_crvboxhgcm.mutex);
683#endif
684    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
685    return pvBuff;
686}
687
688static void _crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
689{
690    int rc;
691    int32_t callRes;
692
693#ifdef IN_GUEST
694    if (conn->u32InjectClientID)
695    {
696        CRVBOXHGCMINJECT parms;
697
698        VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_INJECT, SHCRGL_CPARMS_INJECT);
699
700        parms.u32ClientID.type       = VMMDevHGCMParmType_32bit;
701        parms.u32ClientID.u.value32  = conn->u32InjectClientID;
702
703        parms.pBuffer.type                   = VMMDevHGCMParmType_LinAddr_In;
704        parms.pBuffer.u.Pointer.size         = len;
705        parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
706
707        rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
708        callRes = parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
709    }
710    else
711#endif
712    {
713        CRVBOXHGCMWRITE parms;
714
715        VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE, SHCRGL_CPARMS_WRITE);
716
717        parms.pBuffer.type                   = VMMDevHGCMParmType_LinAddr_In;
718        parms.pBuffer.u.Pointer.size         = len;
719        parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
720
721        rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
722        callRes = parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
723    }
724
725    if (RT_FAILURE(rc) || RT_FAILURE(callRes))
726    {
727        crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
728    }
729}
730
731static void crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
732{
733    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
734#ifdef CHROMIUM_THREADSAFE
735    crLockMutex(&g_crvboxhgcm.mutex);
736#endif
737    _crVBoxHGCMWriteExact(conn, buf, len);
738#ifdef CHROMIUM_THREADSAFE
739    crUnlockMutex(&g_crvboxhgcm.mutex);
740#endif
741    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
742}
743
744static void crVBoxHGCMReadExact( CRConnection *conn, const void *buf, unsigned int len )
745{
746    CRVBOXHGCMREAD parms;
747    int rc;
748    RT_NOREF(buf, len);
749
750    VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_READ, SHCRGL_CPARMS_READ);
751
752    CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
753    parms.pBuffer.type                   = VMMDevHGCMParmType_LinAddr_Out;
754    parms.pBuffer.u.Pointer.size         = conn->cbHostBufferAllocated;
755    parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
756
757    parms.cbBuffer.type      = VMMDevHGCMParmType_32bit;
758    parms.cbBuffer.u.value32 = 0;
759
760    rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
761
762    if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
763    {
764        crWarning("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.Hdr.rc);
765        return;
766    }
767
768    if (parms.cbBuffer.u.value32)
769    {
770        /*conn->pBuffer  = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr; */
771        conn->pBuffer  = conn->pHostBuffer;
772        conn->cbBuffer = parms.cbBuffer.u.value32;
773    }
774
775    if (conn->cbBuffer)
776        _crVBoxHGCMReceiveMessage(conn);
777
778}
779
780/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
781 * This halves the number of HGCM calls we do,
782 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
783 */
784static void
785crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, CRVBOXHGCMBUFFERKIND bufferKind)
786{
787    CRVBOXHGCMWRITEREAD parms;
788    int rc;
789
790    VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE_READ, SHCRGL_CPARMS_WRITE_READ);
791
792    parms.pBuffer.type                   = VMMDevHGCMParmType_LinAddr_In;
793    parms.pBuffer.u.Pointer.size         = len;
794    parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
795
796    CRASSERT(!conn->pBuffer); /*make sure there's no data to process*/
797    parms.pWriteback.type                   = VMMDevHGCMParmType_LinAddr_Out;
798    parms.pWriteback.u.Pointer.size         = conn->cbHostBufferAllocated;
799    parms.pWriteback.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
800
801    parms.cbWriteback.type      = VMMDevHGCMParmType_32bit;
802    parms.cbWriteback.u.value32 = 0;
803
804    rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
805
806#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
807    if (VERR_OUT_OF_RANGE==rc && CR_VBOXHGCM_USERALLOCATED==bufferKind)
808    {
809        /*Buffer is too big, so send it in split chunks*/
810        CRVBOXHGCMWRITEBUFFER wbParms;
811
812        VBGL_HGCM_HDR_INIT(&wbParms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE_BUFFER, SHCRGL_CPARMS_WRITE_BUFFER);
813
814        wbParms.iBufferID.type = VMMDevHGCMParmType_32bit;
815        wbParms.iBufferID.u.value32 = 0;
816
817        wbParms.cbBufferSize.type = VMMDevHGCMParmType_32bit;
818        wbParms.cbBufferSize.u.value32 = len;
819
820        wbParms.ui32Offset.type = VMMDevHGCMParmType_32bit;
821        wbParms.ui32Offset.u.value32 = 0;
822
823        wbParms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
824        wbParms.pBuffer.u.Pointer.size         = MIN(CR_HGCM_SPLIT_BUFFER_SIZE, len);
825        wbParms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
826
827        if (len<CR_HGCM_SPLIT_BUFFER_SIZE)
828        {
829            crError("VERR_OUT_OF_RANGE in crVBoxHGCMWriteReadExact for %u bytes write", len);
830            return;
831        }
832
833        while (wbParms.pBuffer.u.Pointer.size)
834        {
835            crDebug("SHCRGL_GUEST_FN_WRITE_BUFFER, offset=%u, size=%u", wbParms.ui32Offset.u.value32, wbParms.pBuffer.u.Pointer.size);
836
837            rc = crVBoxHGCMCall(conn, &wbParms.hdr, sizeof(wbParms));
838            if (RT_FAILURE(rc) || RT_FAILURE(wbParms.hdr.Hdr.rc) /** @todo now rc == wbParms.hdr.Hdr.rc */)
839            {
840                crError("SHCRGL_GUEST_FN_WRITE_BUFFER (%i) failed with %x %x\n", wbParms.pBuffer.u.Pointer.size, rc, wbParms.hdr.Hdr.rc);
841                return;
842            }
843
844            wbParms.ui32Offset.u.value32 += wbParms.pBuffer.u.Pointer.size;
845            wbParms.pBuffer.u.Pointer.u.linearAddr += (uintptr_t) wbParms.pBuffer.u.Pointer.size;
846            wbParms.pBuffer.u.Pointer.size = MIN(CR_HGCM_SPLIT_BUFFER_SIZE, len-wbParms.ui32Offset.u.value32);
847        }
848
849        /*now issue GUEST_FN_WRITE_READ_BUFFERED referencing the buffer we'd made*/
850        {
851            CRVBOXHGCMWRITEREADBUFFERED wrbParms;
852
853            VBGL_HGCM_HDR_INIT(&wrbParms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE_READ_BUFFERED, SHCRGL_CPARMS_WRITE_READ_BUFFERED);
854
855            crMemcpy(&wrbParms.iBufferID, &wbParms.iBufferID, sizeof(HGCMFunctionParameter));
856            crMemcpy(&wrbParms.pWriteback, &parms.pWriteback, sizeof(HGCMFunctionParameter));
857            crMemcpy(&wrbParms.cbWriteback, &parms.cbWriteback, sizeof(HGCMFunctionParameter));
858
859            rc = crVBoxHGCMCall(conn, &wrbParms.hdr, sizeof(wrbParms));
860
861            /*bit of hack to reuse code below*/
862            parms.hdr.Hdr.rc = wrbParms.hdr.Hdr.rc;
863            crMemcpy(&parms.cbWriteback, &wrbParms.cbWriteback, sizeof(HGCMFunctionParameter));
864            crMemcpy(&parms.pWriteback, &wrbParms.pWriteback, sizeof(HGCMFunctionParameter));
865        }
866    }
867#endif
868
869    if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
870    {
871
872        if ((VERR_BUFFER_OVERFLOW == parms.hdr.Hdr.rc) /* && RT_SUCCESS(rc) */)
873        {
874            /* reallocate buffer and retry */
875
876            CRASSERT(parms.cbWriteback.u.value32>conn->cbHostBufferAllocated);
877
878            crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, parms.cbWriteback.u.value32);
879
880            crFree(conn->pHostBuffer);
881            conn->cbHostBufferAllocated = parms.cbWriteback.u.value32;
882            conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
883
884            crVBoxHGCMReadExact(conn, buf, len);
885
886            return;
887        }
888        else
889        {
890            crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x %x\n", len, rc, parms.hdr.Hdr.rc);
891            return;
892        }
893    }
894
895    if (parms.cbWriteback.u.value32)
896    {
897        /*conn->pBuffer  = (uint8_t*) parms.pWriteback.u.Pointer.u.linearAddr;*/
898        conn->pBuffer  = conn->pHostBuffer;
899        conn->cbBuffer = parms.cbWriteback.u.value32;
900    }
901
902    if (conn->cbBuffer)
903        _crVBoxHGCMReceiveMessage(conn);
904}
905
906static void crVBoxHGCMSend(CRConnection *conn, void **bufp,
907                           const void *start, unsigned int len)
908{
909    CRVBOXHGCMBUFFER *hgcm_buffer;
910    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
911
912#ifdef CHROMIUM_THREADSAFE
913    crLockMutex(&g_crvboxhgcm.mutex);
914#endif
915
916    if (!bufp) /* We're sending a user-allocated buffer. */
917    {
918#ifndef IN_GUEST
919            /** @todo remove temp buffer allocation in unpacker*/
920            /* we're at the host side, so just store data until guest polls us */
921            _crVBoxHGCMWriteBytes(conn, start, len);
922#else
923            CRASSERT(!conn->u32InjectClientID);
924            crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
925            crVBoxHGCMWriteReadExact(conn, start, len, CR_VBOXHGCM_USERALLOCATED);
926#endif
927#ifdef CHROMIUM_THREADSAFE
928            crUnlockMutex(&g_crvboxhgcm.mutex);
929#endif
930            VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
931        return;
932    }
933
934    /* The region [start .. start + len + 1] lies within a buffer that
935     * was allocated with crVBoxHGCMAlloc() and can be put into the free
936     * buffer pool when we're done sending it.
937     */
938
939    hgcm_buffer = (CRVBOXHGCMBUFFER *)(*bufp) - 1;
940    CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
941
942    /* Length would be passed as part of HGCM pointer description
943     * No need to prepend it to the buffer
944     */
945#ifdef IN_GUEST
946    if (conn->u32InjectClientID)
947    {
948        _crVBoxHGCMWriteExact(conn, start, len);
949    }
950    else
951#endif
952    crVBoxHGCMWriteReadExact(conn, start, len, hgcm_buffer->kind);
953
954    /* Reclaim this pointer for reuse */
955#ifdef CHROMIUM_THREADSAFE
956    crLockMutex(&g_crvboxhgcm.mutex);
957#endif
958    crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
959#ifdef CHROMIUM_THREADSAFE
960    crUnlockMutex(&g_crvboxhgcm.mutex);
961#endif
962
963    /* Since the buffer's now in the 'free' buffer pool, the caller can't
964     * use it any more.  Setting bufp to NULL will make sure the caller
965     * doesn't try to re-use the buffer.
966     */
967    *bufp = NULL;
968
969#ifdef CHROMIUM_THREADSAFE
970    crUnlockMutex(&g_crvboxhgcm.mutex);
971#endif
972
973    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
974}
975
976static void crVBoxHGCMPollHost(CRConnection *conn)
977{
978    CRVBOXHGCMREAD parms;
979    int rc;
980
981    CRASSERT(!conn->pBuffer);
982
983    VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_READ, SHCRGL_CPARMS_READ);
984
985    parms.pBuffer.type                   = VMMDevHGCMParmType_LinAddr_Out;
986    parms.pBuffer.u.Pointer.size         = conn->cbHostBufferAllocated;
987    parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
988
989    parms.cbBuffer.type      = VMMDevHGCMParmType_32bit;
990    parms.cbBuffer.u.value32 = 0;
991
992    rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
993
994    if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
995    {
996        crDebug("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.Hdr.rc);
997        return;
998    }
999
1000    if (parms.cbBuffer.u.value32)
1001    {
1002        conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
1003        conn->cbBuffer = parms.cbBuffer.u.value32;
1004    }
1005}
1006
1007static void crVBoxHGCMSingleRecv(CRConnection *conn, void *buf, unsigned int len)
1008{
1009    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1010#ifdef CHROMIUM_THREADSAFE
1011    crLockMutex(&g_crvboxhgcm.mutex);
1012#endif
1013    crVBoxHGCMReadExact(conn, buf, len);
1014#ifdef CHROMIUM_THREADSAFE
1015    crUnlockMutex(&g_crvboxhgcm.mutex);
1016#endif
1017    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1018}
1019
1020static void _crVBoxHGCMFree(CRConnection *conn, void *buf)
1021{
1022    CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1023
1024    CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1025
1026    /** @todo wrong len for redir buffers*/
1027    conn->recv_credits += hgcm_buffer->len;
1028
1029    switch (hgcm_buffer->kind)
1030    {
1031        case CR_VBOXHGCM_MEMORY:
1032#ifdef CHROMIUM_THREADSAFE
1033            crLockMutex(&g_crvboxhgcm.mutex);
1034#endif
1035            if (g_crvboxhgcm.bufpool) {
1036                /** @todo o'rly? */
1037                /* pool may have been deallocated just a bit earlier in response
1038                 * to a SIGPIPE (Broken Pipe) signal.
1039                 */
1040                crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
1041            }
1042#ifdef CHROMIUM_THREADSAFE
1043            crUnlockMutex(&g_crvboxhgcm.mutex);
1044#endif
1045            break;
1046
1047        case CR_VBOXHGCM_MEMORY_BIG:
1048            crFree( hgcm_buffer );
1049            break;
1050
1051        default:
1052            crError( "Weird buffer kind trying to free in crVBoxHGCMFree: %d", hgcm_buffer->kind );
1053    }
1054}
1055
1056static void crVBoxHGCMFree(CRConnection *conn, void *buf)
1057{
1058    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1059#ifdef CHROMIUM_THREADSAFE
1060    crLockMutex(&g_crvboxhgcm.mutex);
1061#endif
1062    _crVBoxHGCMFree(conn, buf);
1063#ifdef CHROMIUM_THREADSAFE
1064    crUnlockMutex(&g_crvboxhgcm.mutex);
1065#endif
1066    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1067}
1068
1069static void _crVBoxHGCMReceiveMessage(CRConnection *conn)
1070{
1071    uint32_t len;
1072    CRVBOXHGCMBUFFER *hgcm_buffer;
1073    CRMessage *msg;
1074    CRMessageType cached_type;
1075
1076    len = conn->cbBuffer;
1077    CRASSERT(len > 0);
1078    CRASSERT(conn->pBuffer);
1079
1080#ifndef IN_GUEST
1081    if (conn->allow_redir_ptr)
1082    {
1083#endif
1084        CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
1085
1086        hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1087        hgcm_buffer->len = sizeof(CRMessageRedirPtr);
1088
1089        msg = (CRMessage *) (hgcm_buffer + 1);
1090
1091        msg->header.type = CR_MESSAGE_REDIR_PTR;
1092        msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
1093        msg->header.conn_id = msg->redirptr.pMessage->conn_id;
1094
1095#if defined(VBOX_WITH_CRHGSMI) && !defined(IN_GUEST)
1096        msg->redirptr.CmdData = conn->CmdData;
1097        CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&msg->redirptr.CmdData);
1098        CRVBOXHGSMI_CMDDATA_CLEANUP(&conn->CmdData);
1099#endif
1100
1101        cached_type = msg->redirptr.pMessage->type;
1102
1103        conn->cbBuffer = 0;
1104        conn->pBuffer  = NULL;
1105#ifndef IN_GUEST
1106    }
1107    else
1108    {
1109        /* we should NEVER have redir_ptr disabled with HGSMI command now */
1110        CRASSERT(!conn->CmdData.pvCmd);
1111        if ( len <= conn->buffer_size )
1112        {
1113            /* put in pre-allocated buffer */
1114            hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1115        }
1116        else
1117        {
1118            /* allocate new buffer,
1119             * not using pool here as it's most likely one time transfer of huge texture
1120             */
1121            hgcm_buffer            = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
1122            hgcm_buffer->magic     = CR_VBOXHGCM_BUFFER_MAGIC;
1123            hgcm_buffer->kind      = CR_VBOXHGCM_MEMORY_BIG;
1124            hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
1125        }
1126
1127        hgcm_buffer->len = len;
1128        _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
1129
1130        msg = (CRMessage *) (hgcm_buffer + 1);
1131        cached_type = msg->header.type;
1132    }
1133#endif /* !IN_GUEST*/
1134
1135    conn->recv_credits     -= len;
1136    conn->total_bytes_recv += len;
1137    conn->recv_count++;
1138
1139    crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
1140
1141    /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
1142     * OOB messages are the programmer's problem.  -- Humper 12/17/01
1143     */
1144    if (cached_type != CR_MESSAGE_OPCODES
1145        && cached_type != CR_MESSAGE_OOB
1146        && cached_type != CR_MESSAGE_GATHER)
1147    {
1148        _crVBoxHGCMFree(conn, msg);
1149    }
1150}
1151
1152static void crVBoxHGCMReceiveMessage(CRConnection *conn)
1153{
1154    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1155#ifdef CHROMIUM_THREADSAFE
1156    crLockMutex(&g_crvboxhgcm.mutex);
1157#endif
1158    _crVBoxHGCMReceiveMessage(conn);
1159#ifdef CHROMIUM_THREADSAFE
1160    crUnlockMutex(&g_crvboxhgcm.mutex);
1161#endif
1162    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1163}
1164
1165
1166/*
1167 * Called on host side only, to "accept" client connection
1168 */
1169static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
1170{
1171    RT_NOREF(hostname, port);
1172    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1173    CRASSERT(conn && conn->pHostBuffer);
1174#ifdef IN_GUEST
1175    CRASSERT(FALSE);
1176#endif
1177    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1178}
1179
1180static int crVBoxHGCMSetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
1181{
1182    CRVBOXHGCMSETVERSION parms;
1183    int rc;
1184    RT_NOREF(vMajor, vMinor);
1185
1186    VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_VERSION, SHCRGL_CPARMS_SET_VERSION);
1187
1188    parms.vMajor.type      = VMMDevHGCMParmType_32bit;
1189    parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
1190    parms.vMinor.type      = VMMDevHGCMParmType_32bit;
1191    parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
1192
1193    rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
1194
1195    if (RT_SUCCESS(rc))
1196    {
1197        rc =  parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
1198        if (RT_SUCCESS(rc))
1199        {
1200            conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
1201            conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
1202
1203            return VINF_SUCCESS;
1204        }
1205        else
1206            WARN(("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
1207                  parms.vMajor.u.value32, parms.vMinor.u.value32));
1208    }
1209    else
1210        WARN(("crVBoxHGCMCall failed %d", rc));
1211
1212    return rc;
1213}
1214
1215static int crVBoxHGCMGetHostCapsLegacy(CRConnection *conn, uint32_t *pu32HostCaps)
1216{
1217    CRVBOXHGCMGETCAPS caps;
1218    int rc;
1219
1220    VBGL_HGCM_HDR_INIT(&caps.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_GET_CAPS_LEGACY, SHCRGL_CPARMS_GET_CAPS_LEGACY);
1221
1222    caps.Caps.type       = VMMDevHGCMParmType_32bit;
1223    caps.Caps.u.value32  = 0;
1224
1225    rc = crVBoxHGCMCall(conn, &caps.hdr, sizeof(caps));
1226
1227    if (RT_SUCCESS(rc))
1228    {
1229        rc = caps.hdr.Hdr.rc;
1230        if (RT_SUCCESS(rc))
1231        {
1232            *pu32HostCaps = caps.Caps.u.value32;
1233            return VINF_SUCCESS;
1234        }
1235        else
1236            WARN(("SHCRGL_GUEST_FN_GET_CAPS failed %d", rc));
1237        return FALSE;
1238    }
1239    else
1240        WARN(("crVBoxHGCMCall failed %d", rc));
1241
1242    *pu32HostCaps = 0;
1243
1244    return rc;
1245}
1246
1247static int crVBoxHGCMSetPID(CRConnection *conn, unsigned long long pid)
1248{
1249    CRVBOXHGCMSETPID parms;
1250    int rc;
1251
1252    VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_PID, SHCRGL_CPARMS_SET_PID);
1253
1254    parms.u64PID.type      = VMMDevHGCMParmType_64bit;
1255    parms.u64PID.u.value64 = pid;
1256
1257    rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
1258
1259    if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
1260    {
1261        crWarning("SHCRGL_GUEST_FN_SET_PID failed!");
1262        return FALSE;
1263    }
1264
1265    return TRUE;
1266}
1267
1268/**
1269 * The function that actually connects.  This should only be called by clients,
1270 * guests in vbox case.
1271 * Servers go through crVBoxHGCMAccept;
1272 */
1273static int crVBoxHGCMDoConnect( CRConnection *conn )
1274{
1275#ifdef IN_GUEST
1276    int rc;
1277    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1278    RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
1279    rc = VbglR3InitUser();
1280    if (RT_SUCCESS(rc))
1281    {
1282        uint32_t idClient;
1283        rc = VbglR3HGCMConnect("VBoxSharedCrOpenGL", &idClient);
1284        if (RT_SUCCESS(rc))
1285        {
1286            conn->u32ClientID = idClient;
1287            crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
1288
1289            rc = crVBoxHGCMSetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
1290            if (RT_FAILURE(rc))
1291            {
1292                WARN(("crVBoxHGCMSetVersion failed %d", rc));
1293                return FALSE;
1294            }
1295#ifdef RT_OS_WINDOWS
1296            rc = crVBoxHGCMSetPID(conn, GetCurrentProcessId());
1297#else
1298            rc = crVBoxHGCMSetPID(conn, crGetPID());
1299#endif
1300            if (RT_FAILURE(rc))
1301            {
1302                WARN(("crVBoxHGCMSetPID failed %Rrc", rc));
1303                return FALSE;
1304            }
1305
1306            if (!g_crvboxhgcm.fHostCapsInitialized)
1307            {
1308                rc = crVBoxHGCMGetHostCapsLegacy(conn, &g_crvboxhgcm.u32HostCaps);
1309                if (RT_FAILURE(rc))
1310                {
1311                    WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %Rrc", rc));
1312                    g_crvboxhgcm.u32HostCaps = 0;
1313                }
1314
1315                /* host may not support it, ignore any failures */
1316                g_crvboxhgcm.fHostCapsInitialized = true;
1317            }
1318
1319            if (g_crvboxhgcm.u32HostCaps & CR_VBOX_CAP_HOST_CAPS_NOT_SUFFICIENT)
1320            {
1321                crDebug("HGCM connect: insufficient host capabilities\n");
1322                g_crvboxhgcm.u32HostCaps = 0;
1323                return FALSE;
1324            }
1325
1326            VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1327            return TRUE;
1328        }
1329
1330        crDebug("HGCM connect failed: %Rrc\n", rc);
1331        VbglR3Term();
1332    }
1333    else
1334        crDebug("Failed to initialize VbglR3 library: %Rrc\n", rc);
1335
1336    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1337    return FALSE;
1338
1339#else  /* !IN_GUEST */
1340    crError("crVBoxHGCMDoConnect called on host side!");
1341    CRASSERT(FALSE);
1342    return FALSE;
1343#endif /* !IN_GUEST */
1344}
1345
1346static bool _crVBoxCommonDoDisconnectLocked( CRConnection *conn )
1347{
1348    int i;
1349    if (conn->pHostBuffer)
1350    {
1351        crFree(conn->pHostBuffer);
1352        conn->pHostBuffer = NULL;
1353        conn->cbHostBuffer = 0;
1354        conn->cbHostBufferAllocated = 0;
1355    }
1356
1357    conn->pBuffer = NULL;
1358    conn->cbBuffer = 0;
1359
1360    if (conn->type == CR_VBOXHGCM)
1361    {
1362        --g_crvboxhgcm.num_conns;
1363
1364        if (conn->index < g_crvboxhgcm.num_conns)
1365        {
1366            g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
1367            g_crvboxhgcm.conns[conn->index]->index = conn->index;
1368        }
1369        else g_crvboxhgcm.conns[conn->index] = NULL;
1370
1371        conn->type = CR_NO_CONNECTION;
1372    }
1373
1374    for (i = 0; i < g_crvboxhgcm.num_conns; i++)
1375        if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
1376            return true;
1377    return false;
1378}
1379
1380/** @todo same, replace DeviceIoControl with vbglR3DoIOCtl */
1381static void crVBoxHGCMDoDisconnect( CRConnection *conn )
1382{
1383    bool fHasActiveCons = false;
1384
1385    if (!g_crvboxhgcm.initialized) return;
1386
1387#ifdef CHROMIUM_THREADSAFE
1388    crLockMutex(&g_crvboxhgcm.mutex);
1389#endif
1390
1391    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1392
1393    fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
1394
1395#ifndef IN_GUEST
1396#else /* IN_GUEST */
1397    if (conn->u32ClientID)
1398    {
1399        int rc = VbglR3HGCMDisconnect(conn->u32ClientID);
1400        if (RT_FAILURE(rc))
1401            crDebug("Disconnect failed with %Rrc\n", rc);
1402        conn->u32ClientID = 0;
1403
1404        VbglR3Term();
1405    }
1406#endif /* IN_GUEST */
1407
1408    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1409
1410#ifdef CHROMIUM_THREADSAFE
1411    crUnlockMutex(&g_crvboxhgcm.mutex);
1412#endif
1413}
1414
1415static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
1416{
1417    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1418#ifdef CHROMIUM_THREADSAFE
1419    crLockMutex(&g_crvboxhgcm.mutex);
1420#endif
1421    _crVBoxHGCMFree(conn, mess);
1422    CRASSERT(FALSE);
1423#ifdef CHROMIUM_THREADSAFE
1424    crUnlockMutex(&g_crvboxhgcm.mutex);
1425#endif
1426    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1427}
1428
1429static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1430{
1431    RT_NOREF(conn, msg, len);
1432    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1433    CRASSERT(FALSE);
1434    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1435}
1436
1437#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1438
1439bool _crVBoxHGSMIInit()
1440{
1441#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1442    static
1443#endif
1444    int bHasHGSMI = -1;
1445
1446    if (bHasHGSMI < 0)
1447    {
1448        int rc;
1449        rc = VBoxCrHgsmiInit();
1450        if (RT_SUCCESS(rc))
1451            bHasHGSMI = 1;
1452        else
1453            bHasHGSMI = 0;
1454
1455        crDebug("CrHgsmi is %s", bHasHGSMI ? "ENABLED" : "DISABLED");
1456    }
1457
1458    CRASSERT(bHasHGSMI >= 0);
1459
1460    return bHasHGSMI;
1461}
1462
1463void _crVBoxHGSMITearDown()
1464{
1465    VBoxCrHgsmiTerm();
1466}
1467
1468static void *_crVBoxHGSMIDoAlloc(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1469{
1470    PVBOXUHGSMI_BUFFER buf;
1471    CRVBOXHGCMBUFFER *pData = NULL;
1472    uint32_t cbSize = conn->buffer_size;
1473    int rc;
1474
1475    buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
1476    if (buf)
1477    {
1478        VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1479        buf->pvUserData = pClient;
1480        fFlags.Value = 0;
1481        fFlags.bDiscard = 1;
1482        rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
1483        if (RT_SUCCESS(rc))
1484        {
1485            pData->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1486            pData->kind = CR_VBOXHGCM_UHGSMI_BUFFER;
1487            pData->pBuffer = buf;
1488        }
1489        else
1490        {
1491            crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
1492        }
1493        return CRVBOXHGSMI_BUF_DATA(pData);
1494    }
1495    else
1496    {
1497        crWarning("_crVBoxHGSMIBufAlloc failed to allocate buffer of size (%d)", CRVBOXHGSMI_BUF_SIZE(cbSize));
1498    }
1499
1500    /* fall back */
1501    return _crVBoxHGCMAlloc(conn);
1502}
1503
1504static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
1505{
1506    CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1507
1508    CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1509
1510    if (hgcm_buffer->kind == CR_VBOXHGCM_UHGSMI_BUFFER)
1511    {
1512        PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1513        PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1514        _crVBoxHGSMIBufFree(pClient, pBuf);
1515    }
1516    else
1517    {
1518        _crVBoxHGCMFree(conn, buf);
1519    }
1520}
1521
1522static void *crVBoxHGSMIAlloc(CRConnection *conn)
1523{
1524    PCRVBOXHGSMI_CLIENT pClient;
1525    void *pvBuf;
1526
1527    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1528
1529#ifdef CHROMIUM_THREADSAFE
1530    crLockMutex(&g_crvboxhgcm.mutex);
1531#endif
1532
1533    pClient = _crVBoxHGSMIClientGet(conn);
1534    if (pClient)
1535    {
1536        pvBuf = _crVBoxHGSMIDoAlloc(conn, pClient);
1537        CRASSERT(pvBuf);
1538    }
1539    else
1540    {
1541        pvBuf = _crVBoxHGCMAlloc(conn);
1542    }
1543
1544#ifdef CHROMIUM_THREADSAFE
1545    crUnlockMutex(&g_crvboxhgcm.mutex);
1546#endif
1547
1548    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1549
1550    return pvBuf;
1551}
1552
1553static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
1554{
1555    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1556#ifdef CHROMIUM_THREADSAFE
1557    crLockMutex(&g_crvboxhgcm.mutex);
1558#endif
1559    _crVBoxHGSMIFree(conn, buf);
1560#ifdef CHROMIUM_THREADSAFE
1561    crUnlockMutex(&g_crvboxhgcm.mutex);
1562#endif
1563    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1564}
1565
1566static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1567{
1568    CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1569    int rc;
1570    VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1571    PVBOXUHGSMI_BUFFER pRecvBuffer;
1572    uint32_t cbBuffer;
1573
1574    CRASSERT(parms);
1575
1576    parms->hdr.result      = VERR_WRONG_ORDER;
1577    parms->hdr.u32ClientID = conn->u32ClientID;
1578    parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
1579/*    parms->hdr.u32Reserved = 0;*/
1580
1581    CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
1582    parms->iBuffer = 1;
1583    parms->cbBuffer = 0;
1584
1585    _crVBoxHGSMICmdBufferUnlock(pClient);
1586
1587    pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1588    CRASSERT(pRecvBuffer);
1589    if (!pRecvBuffer)
1590        return;
1591
1592    _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1593
1594    aSubmit[1].pBuf = pRecvBuffer;
1595    aSubmit[1].offData = 0;
1596    aSubmit[1].cbData = pRecvBuffer->cbBuffer;
1597    aSubmit[1].fFlags.Value = 0;
1598    aSubmit[1].fFlags.bHostWriteOnly = 1;
1599
1600    rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1601    if (RT_FAILURE(rc))
1602    {
1603        crError("pfnBufferSubmit failed with %d \n", rc);
1604        return;
1605    }
1606
1607    parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1608    CRASSERT(parms);
1609    if (!parms)
1610    {
1611        crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1612        return;
1613    }
1614
1615    if (RT_SUCCESS(parms->hdr.result))
1616        cbBuffer = parms->cbBuffer;
1617    else
1618        cbBuffer = 0;
1619
1620    _crVBoxHGSMICmdBufferUnlock(pClient);
1621
1622    if (cbBuffer)
1623    {
1624        void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
1625        CRASSERT(pvData);
1626        if (pvData)
1627        {
1628            conn->pBuffer  = pvData;
1629            conn->cbBuffer = cbBuffer;
1630        }
1631    }
1632}
1633
1634static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1635{
1636    _crVBoxHGSMIPollHost(conn, pClient);
1637
1638    if (conn->cbBuffer)
1639        _crVBoxHGCMReceiveMessage(conn);
1640}
1641
1642/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
1643 * This halves the number of HGCM calls we do,
1644 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
1645 */
1646static void
1647_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
1648{
1649    CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1650    int rc;
1651    VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
1652    PVBOXUHGSMI_BUFFER pBuf = NULL;
1653    VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1654/*    uint32_t cbBuffer;*/
1655
1656    parms->hdr.result      = VERR_WRONG_ORDER;
1657    parms->hdr.u32ClientID = conn->u32ClientID;
1658    parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
1659/*    parms->hdr.u32Reserved = 0;*/
1660
1661    parms->iBuffer = 1;
1662
1663    CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
1664    parms->iWriteback = 2;
1665    parms->cbWriteback = 0;
1666
1667    _crVBoxHGSMICmdBufferUnlock(pClient);
1668
1669    if (!bIsBuffer)
1670    {
1671        void *pvBuf;
1672        pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
1673
1674        if (!pBuf)
1675        {
1676            /* fallback */
1677            crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1678            return;
1679        }
1680
1681        CRASSERT(!offBuffer);
1682
1683        offBuffer = 0;
1684        fFlags.Value = 0;
1685        fFlags.bDiscard = 1;
1686        fFlags.bWriteOnly = 1;
1687        rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
1688        if (RT_SUCCESS(rc))
1689        {
1690            memcpy(pvBuf, buf, len);
1691            rc = pBuf->pfnUnlock(pBuf);
1692            CRASSERT(RT_SUCCESS(rc));
1693        }
1694        else
1695        {
1696            crWarning("_crVBoxHGSMIWriteReadExact: pfnUnlock failed rc %d", rc);
1697            _crVBoxHGSMIBufFree(pClient, pBuf);
1698            /* fallback */
1699            crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1700            return;
1701        }
1702    }
1703    else
1704    {
1705        pBuf = (PVBOXUHGSMI_BUFFER)buf;
1706    }
1707
1708    do
1709    {
1710        PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1711        CRASSERT(pRecvBuffer);
1712        if (!pRecvBuffer)
1713        {
1714            break;
1715        }
1716
1717        _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1718
1719        aSubmit[1].pBuf = pBuf;
1720        aSubmit[1].offData = offBuffer;
1721        aSubmit[1].cbData = len;
1722        aSubmit[1].fFlags.Value = 0;
1723        aSubmit[1].fFlags.bHostReadOnly = 1;
1724
1725        aSubmit[2].pBuf = pRecvBuffer;
1726        aSubmit[2].offData = 0;
1727        aSubmit[2].cbData = pRecvBuffer->cbBuffer;
1728        aSubmit[2].fFlags.Value = 0;
1729
1730        rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 3);
1731        if (RT_FAILURE(rc))
1732        {
1733            crError("pfnBufferSubmit failed with %d \n", rc);
1734            break;
1735        }
1736
1737        parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1738        CRASSERT(parms);
1739        if (parms)
1740        {
1741            uint32_t cbWriteback = parms->cbWriteback;
1742            rc = parms->hdr.result;
1743#ifdef DEBUG_misha
1744            /* catch it here to test the buffer */
1745            Assert(RT_SUCCESS(parms->hdr.Hdr.rc) || parms->hdr.Hdr.rc == VERR_BUFFER_OVERFLOW);
1746#endif
1747            _crVBoxHGSMICmdBufferUnlock(pClient);
1748#ifdef DEBUG
1749            parms = NULL;
1750#endif
1751            if (RT_SUCCESS(rc))
1752            {
1753                if (cbWriteback)
1754                {
1755                    void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
1756                    CRASSERT(pvData);
1757                    if (pvData)
1758                    {
1759                        conn->pBuffer  = pvData;
1760                        conn->cbBuffer = cbWriteback;
1761                        _crVBoxHGCMReceiveMessage(conn);
1762                    }
1763                }
1764            }
1765            else if (VERR_BUFFER_OVERFLOW == rc)
1766            {
1767                VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
1768                PVBOXUHGSMI_BUFFER pNewBuf;
1769                CRASSERT(!pClient->pvHGBuffer);
1770                CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
1771                crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
1772
1773                rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pNewBuf);
1774                if (RT_SUCCESS(rc))
1775                {
1776                    rc = pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
1777                    CRASSERT(RT_SUCCESS(rc));
1778
1779                    pClient->pHGBuffer = pNewBuf;
1780
1781                    _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
1782                }
1783                else
1784                {
1785                    crWarning("_crVBoxHGSMIWriteReadExact: pfnBufferCreate(%d) failed!", CRVBOXHGSMI_PAGE_ALIGN(cbWriteback));
1786                    if (conn->cbHostBufferAllocated < cbWriteback)
1787                    {
1788                        crFree(conn->pHostBuffer);
1789                        conn->cbHostBufferAllocated = cbWriteback;
1790                        conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
1791                    }
1792                    crVBoxHGCMReadExact(conn, NULL, cbWriteback);
1793                }
1794            }
1795            else
1796            {
1797                crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
1798            }
1799        }
1800        else
1801        {
1802            crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1803            break;
1804        }
1805    } while (0);
1806
1807    if (!bIsBuffer)
1808        _crVBoxHGSMIBufFree(pClient, pBuf);
1809
1810    return;
1811}
1812
1813static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
1814{
1815    int rc;
1816    int32_t callRes = VINF_SUCCESS; /* Shut up MSC. */
1817    VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1818
1819#ifdef IN_GUEST
1820    if (conn->u32InjectClientID)
1821    {
1822        CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1823        CRASSERT(parms);
1824        if (!parms)
1825        {
1826            return;
1827        }
1828
1829        parms->hdr.result      = VERR_WRONG_ORDER;
1830        parms->hdr.u32ClientID = conn->u32ClientID;
1831        parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
1832/*        parms->hdr.u32Reserved = 0;*/
1833
1834        parms->u32ClientID = conn->u32InjectClientID;
1835
1836        parms->iBuffer = 1;
1837        _crVBoxHGSMICmdBufferUnlock(pClient);
1838
1839        _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1840
1841        aSubmit[1].pBuf = pBuf;
1842        aSubmit[1].offData = offStart;
1843        aSubmit[1].cbData = len;
1844        aSubmit[1].fFlags.Value = 0;
1845        aSubmit[1].fFlags.bHostReadOnly = 1;
1846
1847        rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1848        if (RT_SUCCESS(rc))
1849        {
1850            callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1851        }
1852        else
1853        {
1854            /* we can not recover at this point, report error & exit */
1855            crError("pfnBufferSubmit failed with %d \n", rc);
1856        }
1857    }
1858    else
1859#endif
1860    {
1861        CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
1862
1863        parms->hdr.result      = VERR_WRONG_ORDER;
1864        parms->hdr.u32ClientID = conn->u32ClientID;
1865        parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
1866/*        parms->hdr.u32Reserved = 0; */
1867
1868        parms->iBuffer = 1;
1869        _crVBoxHGSMICmdBufferUnlock(pClient);
1870
1871        _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1872
1873        aSubmit[1].pBuf = pBuf;
1874        aSubmit[1].offData = offStart;
1875        aSubmit[1].cbData = len;
1876        aSubmit[1].fFlags.Value = 0;
1877        aSubmit[1].fFlags.bHostReadOnly = 1;
1878
1879        rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1880        if (RT_SUCCESS(rc))
1881        {
1882            callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1883        }
1884        else
1885        {
1886            /* we can not recover at this point, report error & exit */
1887            crError("Failed to submit CrHhgsmi buffer");
1888        }
1889    }
1890
1891    if (RT_FAILURE(rc) || RT_FAILURE(callRes))
1892    {
1893        crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
1894    }
1895}
1896
1897static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
1898                           const void *start, unsigned int len)
1899{
1900    PCRVBOXHGSMI_CLIENT pClient;
1901    PVBOXUHGSMI_BUFFER pBuf;
1902    CRVBOXHGCMBUFFER *hgcm_buffer;
1903
1904    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1905
1906#ifdef CHROMIUM_THREADSAFE
1907    crLockMutex(&g_crvboxhgcm.mutex);
1908#endif
1909
1910    if (!bufp) /* We're sending a user-allocated buffer. */
1911    {
1912        pClient = _crVBoxHGSMIClientGet(conn);
1913        if (pClient)
1914        {
1915#ifndef IN_GUEST
1916                /** @todo remove temp buffer allocation in unpacker */
1917                /* we're at the host side, so just store data until guest polls us */
1918                _crVBoxHGCMWriteBytes(conn, start, len);
1919#else
1920            CRASSERT(!conn->u32InjectClientID);
1921            crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
1922            _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
1923#endif
1924#ifdef CHROMIUM_THREADSAFE
1925            crUnlockMutex(&g_crvboxhgcm.mutex);
1926#endif
1927            VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1928            return;
1929        }
1930
1931        /* fallback */
1932        crVBoxHGCMSend(conn, bufp, start, len);
1933#ifdef CHROMIUM_THREADSAFE
1934        crUnlockMutex(&g_crvboxhgcm.mutex);
1935#endif
1936        VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1937        return;
1938    }
1939
1940    hgcm_buffer = (CRVBOXHGCMBUFFER *) *bufp - 1;
1941    CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1942    if (hgcm_buffer->magic != CR_VBOXHGCM_BUFFER_MAGIC)
1943    {
1944        crError("HGCM buffer magic mismatch");
1945    }
1946
1947
1948    if (hgcm_buffer->kind != CR_VBOXHGCM_UHGSMI_BUFFER)
1949    {
1950        /* fallback */
1951        crVBoxHGCMSend(conn, bufp, start, len);
1952#ifdef CHROMIUM_THREADSAFE
1953        crUnlockMutex(&g_crvboxhgcm.mutex);
1954#endif
1955        VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1956        return;
1957    }
1958
1959    /* The region [start .. start + len + 1] lies within a buffer that
1960     * was allocated with crVBoxHGCMAlloc() and can be put into the free
1961     * buffer pool when we're done sending it.
1962     */
1963
1964    pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1965    CRASSERT(pBuf);
1966    if (!pBuf)
1967    {
1968        crVBoxHGCMSend(conn, bufp, start, len);
1969#ifdef CHROMIUM_THREADSAFE
1970        crUnlockMutex(&g_crvboxhgcm.mutex);
1971#endif
1972        VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1973        return;
1974    }
1975
1976    pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1977    if (pClient != &conn->HgsmiClient)
1978    {
1979        crError("HGSMI client mismatch");
1980    }
1981
1982    /* Length would be passed as part of HGCM pointer description
1983     * No need to prepend it to the buffer
1984     */
1985#ifdef IN_GUEST
1986    if (conn->u32InjectClientID)
1987    {
1988        _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
1989    }
1990    else
1991#endif
1992    {
1993        _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
1994    }
1995
1996    /* Reclaim this pointer for reuse */
1997    _crVBoxHGSMIBufFree(pClient, pBuf);
1998    /* Since the buffer's now in the 'free' buffer pool, the caller can't
1999     * use it any more.  Setting bufp to NULL will make sure the caller
2000     * doesn't try to re-use the buffer.
2001     */
2002    *bufp = NULL;
2003
2004#ifdef CHROMIUM_THREADSAFE
2005    crUnlockMutex(&g_crvboxhgcm.mutex);
2006#endif
2007
2008    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2009}
2010
2011static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
2012{
2013    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2014
2015    CRASSERT(0);
2016
2017    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2018}
2019
2020static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
2021{
2022    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2023
2024    CRASSERT(0);
2025
2026    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2027}
2028
2029static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
2030{
2031    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2032
2033#ifdef CHROMIUM_THREADSAFE
2034    crLockMutex(&g_crvboxhgcm.mutex);
2035#endif
2036
2037    CRASSERT(0);
2038
2039    _crVBoxHGCMReceiveMessage(conn);
2040
2041#ifdef CHROMIUM_THREADSAFE
2042    crUnlockMutex(&g_crvboxhgcm.mutex);
2043#endif
2044
2045    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2046}
2047
2048/*
2049 * Called on host side only, to "accept" client connection
2050 */
2051static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
2052{
2053    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2054    CRASSERT(0);
2055
2056    CRASSERT(conn && conn->pHostBuffer);
2057#ifdef IN_GUEST
2058    CRASSERT(FALSE);
2059#endif
2060    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2061}
2062
2063static int crVBoxHGSMIDoConnect( CRConnection *conn )
2064{
2065    PCRVBOXHGSMI_CLIENT pClient;
2066    int rc = VINF_SUCCESS;
2067
2068#ifdef CHROMIUM_THREADSAFE
2069    crLockMutex(&g_crvboxhgcm.mutex);
2070#endif
2071
2072    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2073
2074    pClient = _crVBoxHGSMIClientGet(conn);
2075    if (pClient)
2076    {
2077        rc = VBoxCrHgsmiCtlConGetClientID(pClient->pHgsmi, &conn->u32ClientID);
2078        if (RT_FAILURE(rc))
2079        {
2080            WARN(("VBoxCrHgsmiCtlConGetClientID failed %d", rc));
2081        }
2082        if (!g_crvboxhgcm.fHostCapsInitialized)
2083        {
2084            rc = VBoxCrHgsmiCtlConGetHostCaps(pClient->pHgsmi, &g_crvboxhgcm.u32HostCaps);
2085            if (RT_SUCCESS(rc))
2086            {
2087                g_crvboxhgcm.fHostCapsInitialized = true;
2088            }
2089            else
2090            {
2091                WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %d", rc));
2092                g_crvboxhgcm.u32HostCaps = 0;
2093            }
2094        }
2095    }
2096    else
2097    {
2098        WARN(("_crVBoxHGSMIClientGet failed %d", rc));
2099        rc = VERR_GENERAL_FAILURE;
2100    }
2101
2102    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2103
2104#ifdef CHROMIUM_THREADSAFE
2105    crUnlockMutex(&g_crvboxhgcm.mutex);
2106#endif
2107    return RT_SUCCESS(rc);
2108}
2109
2110static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
2111{
2112    bool fHasActiveCons = false;
2113
2114    if (!g_crvboxhgcm.initialized) return;
2115
2116    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2117
2118#ifdef CHROMIUM_THREADSAFE
2119    crLockMutex(&g_crvboxhgcm.mutex);
2120#endif
2121
2122    fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
2123
2124#ifndef VBOX_CRHGSMI_WITH_D3DDEV
2125    if (conn->HgsmiClient.pHgsmi)
2126    {
2127        PVBOXUHGSMI pHgsmi;
2128        _crVBoxHGSMIClientTerm(&conn->HgsmiClient, &pHgsmi);
2129        CRASSERT(pHgsmi);
2130        if (!conn->pExternalHgsmi)
2131            VBoxCrHgsmiDestroy(pHgsmi);
2132    }
2133#else
2134# error "port me!"
2135#endif
2136
2137    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2138
2139#ifdef CHROMIUM_THREADSAFE
2140    crUnlockMutex(&g_crvboxhgcm.mutex);
2141#endif
2142}
2143
2144static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
2145{
2146    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2147#ifdef CHROMIUM_THREADSAFE
2148    crLockMutex(&g_crvboxhgcm.mutex);
2149#endif
2150    CRASSERT(0);
2151
2152    _crVBoxHGSMIFree(conn, mess);
2153
2154#ifdef CHROMIUM_THREADSAFE
2155    crUnlockMutex(&g_crvboxhgcm.mutex);
2156#endif
2157    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2158}
2159
2160static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
2161{
2162    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2163    CRASSERT(0);
2164
2165    CRASSERT(FALSE);
2166    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2167}
2168#endif
2169
2170void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
2171{
2172    (void) mtu;
2173
2174    g_crvboxhgcm.recv_list = rfl;
2175    g_crvboxhgcm.close_list = cfl;
2176    if (g_crvboxhgcm.initialized)
2177    {
2178        return;
2179    }
2180
2181    VBOXCRHGSMIPROFILE_INIT();
2182
2183    g_crvboxhgcm.initialized = 1;
2184
2185#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2186    g_crvboxhgcm.bHgsmiOn = _crVBoxHGSMIInit();
2187#endif
2188
2189    g_crvboxhgcm.num_conns = 0;
2190    g_crvboxhgcm.conns     = NULL;
2191
2192    /* Can't open VBox guest driver here, because it gets called for host side as well */
2193    /** @todo as we have 2 dll versions, can do it now.*/
2194
2195#ifdef RT_OS_WINDOWS
2196    g_crvboxhgcm.pDirectDraw = NULL;
2197#endif
2198
2199#ifdef CHROMIUM_THREADSAFE
2200    crInitMutex(&g_crvboxhgcm.mutex);
2201    crInitMutex(&g_crvboxhgcm.recvmutex);
2202#endif
2203    g_crvboxhgcm.bufpool = crBufferPoolInit(16);
2204
2205#ifdef IN_GUEST
2206    g_crvboxhgcm.fHostCapsInitialized = false;
2207    g_crvboxhgcm.u32HostCaps = 0;
2208#endif
2209}
2210
2211/* Callback function used to free buffer pool entries */
2212static void crVBoxHGCMBufferFree(void *data)
2213{
2214    CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
2215
2216    CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2217
2218    switch (hgcm_buffer->kind)
2219    {
2220        case CR_VBOXHGCM_MEMORY:
2221            crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY: %p", hgcm_buffer);
2222            crFree( hgcm_buffer );
2223            break;
2224        case CR_VBOXHGCM_MEMORY_BIG:
2225            crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY_BIG: %p", hgcm_buffer);
2226            crFree( hgcm_buffer );
2227            break;
2228
2229        default:
2230            crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
2231    }
2232}
2233
2234void crVBoxHGCMTearDown(void)
2235{
2236    int32_t i, cCons;
2237
2238    if (!g_crvboxhgcm.initialized) return;
2239
2240#ifdef CHROMIUM_THREADSAFE
2241    crLockMutex(&g_crvboxhgcm.mutex);
2242#endif
2243
2244    /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
2245     * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
2246     * order of their connection.
2247     */
2248    cCons = g_crvboxhgcm.num_conns;
2249    for (i=0; i<cCons; i++)
2250    {
2251        /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
2252        crNetDisconnect(g_crvboxhgcm.conns[0]);
2253    }
2254    CRASSERT(0==g_crvboxhgcm.num_conns);
2255
2256    g_crvboxhgcm.initialized = 0;
2257
2258    if (g_crvboxhgcm.bufpool)
2259        crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
2260    g_crvboxhgcm.bufpool = NULL;
2261
2262#ifdef CHROMIUM_THREADSAFE
2263    crUnlockMutex(&g_crvboxhgcm.mutex);
2264    crFreeMutex(&g_crvboxhgcm.mutex);
2265    crFreeMutex(&g_crvboxhgcm.recvmutex);
2266#endif
2267
2268    crFree(g_crvboxhgcm.conns);
2269    g_crvboxhgcm.conns = NULL;
2270
2271#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2272    if (g_crvboxhgcm.bHgsmiOn)
2273    {
2274        _crVBoxHGSMITearDown();
2275    }
2276#endif
2277
2278#ifdef RT_OS_WINDOWS
2279    if (g_crvboxhgcm.pDirectDraw)
2280    {
2281        IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
2282        g_crvboxhgcm.pDirectDraw = NULL;
2283        crDebug("DirectDraw released\n");
2284    }
2285#endif
2286}
2287
2288void crVBoxHGCMConnection(CRConnection *conn
2289#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2290        , struct VBOXUHGSMI *pHgsmi
2291#endif
2292        )
2293{
2294    int i, found = 0;
2295    int n_bytes;
2296
2297    CRASSERT(g_crvboxhgcm.initialized);
2298
2299#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2300    if (g_crvboxhgcm.bHgsmiOn)
2301    {
2302        conn->type = CR_VBOXHGCM;
2303        conn->Alloc = crVBoxHGSMIAlloc;
2304        conn->Send = crVBoxHGSMISend;
2305        conn->SendExact = crVBoxHGSMIWriteExact;
2306        conn->Recv = crVBoxHGSMISingleRecv;
2307        conn->RecvMsg = crVBoxHGSMIReceiveMessage;
2308        conn->Free = crVBoxHGSMIFree;
2309        conn->Accept = crVBoxHGSMIAccept;
2310        conn->Connect = crVBoxHGSMIDoConnect;
2311        conn->Disconnect = crVBoxHGSMIDoDisconnect;
2312        conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
2313        conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
2314        conn->pExternalHgsmi = pHgsmi;
2315    }
2316    else
2317#endif
2318    {
2319        conn->type = CR_VBOXHGCM;
2320        conn->Alloc = crVBoxHGCMAlloc;
2321        conn->Send = crVBoxHGCMSend;
2322        conn->SendExact = crVBoxHGCMWriteExact;
2323        conn->Recv = crVBoxHGCMSingleRecv;
2324        conn->RecvMsg = crVBoxHGCMReceiveMessage;
2325        conn->Free = crVBoxHGCMFree;
2326        conn->Accept = crVBoxHGCMAccept;
2327        conn->Connect = crVBoxHGCMDoConnect;
2328        conn->Disconnect = crVBoxHGCMDoDisconnect;
2329        conn->InstantReclaim = crVBoxHGCMInstantReclaim;
2330        conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
2331    }
2332    conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
2333    conn->actual_network = 1;
2334
2335    conn->krecv_buf_size = 0;
2336
2337    conn->pBuffer = NULL;
2338    conn->cbBuffer = 0;
2339    conn->allow_redir_ptr = 1;
2340
2341    /** @todo remove this crap at all later */
2342    conn->cbHostBufferAllocated = 2*1024;
2343    conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
2344    CRASSERT(conn->pHostBuffer);
2345    conn->cbHostBuffer = 0;
2346
2347#if !defined(IN_GUEST)
2348    RTListInit(&conn->PendingMsgList);
2349#endif
2350
2351#ifdef CHROMIUM_THREADSAFE
2352    crLockMutex(&g_crvboxhgcm.mutex);
2353#endif
2354    /* Find a free slot */
2355    for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
2356        if (g_crvboxhgcm.conns[i] == NULL) {
2357            conn->index = i;
2358            g_crvboxhgcm.conns[i] = conn;
2359            found = 1;
2360            break;
2361        }
2362    }
2363
2364    /* Realloc connection stack if we couldn't find a free slot */
2365    if (found == 0) {
2366        n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
2367        crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
2368        conn->index = g_crvboxhgcm.num_conns;
2369        g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
2370    }
2371#ifdef CHROMIUM_THREADSAFE
2372    crUnlockMutex(&g_crvboxhgcm.mutex);
2373#endif
2374}
2375
2376#if defined(IN_GUEST)
2377static void _crVBoxHGCMPerformPollHost(CRConnection *conn)
2378{
2379    if (conn->type == CR_NO_CONNECTION )
2380        return;
2381
2382    if (!conn->pBuffer)
2383    {
2384#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2385        PCRVBOXHGSMI_CLIENT pClient;
2386        if (g_crvboxhgcm.bHgsmiOn && !!(pClient = _crVBoxHGSMIClientGet(conn)))
2387        {
2388            _crVBoxHGSMIPollHost(conn, pClient);
2389        }
2390        else
2391#endif
2392        {
2393            crVBoxHGCMPollHost(conn);
2394        }
2395    }
2396}
2397#endif
2398
2399static void _crVBoxHGCMPerformReceiveMessage(CRConnection *conn)
2400{
2401    if ( conn->type == CR_NO_CONNECTION )
2402        return;
2403
2404    if (conn->cbBuffer>0)
2405    {
2406        _crVBoxHGCMReceiveMessage(conn);
2407    }
2408}
2409
2410#ifdef IN_GUEST
2411uint32_t crVBoxHGCMHostCapsGet(void)
2412{
2413    Assert(g_crvboxhgcm.fHostCapsInitialized);
2414    return g_crvboxhgcm.u32HostCaps;
2415}
2416#endif
2417
2418int crVBoxHGCMRecv(
2419#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2420        CRConnection *conn
2421#else
2422        void
2423#endif
2424        )
2425{
2426    int32_t i;
2427
2428    VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2429
2430#ifdef CHROMIUM_THREADSAFE
2431    crLockMutex(&g_crvboxhgcm.mutex);
2432#endif
2433
2434#ifdef IN_GUEST
2435# if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2436    if (conn && g_crvboxhgcm.bHgsmiOn)
2437    {
2438        _crVBoxHGCMPerformPollHost(conn);
2439        _crVBoxHGCMPerformReceiveMessage(conn);
2440        VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2441        return 0;
2442    }
2443# endif
2444    /* we're on guest side, poll host if it got something for us */
2445    for (i=0; i<g_crvboxhgcm.num_conns; i++)
2446    {
2447        CRConnection *conn = g_crvboxhgcm.conns[i];
2448
2449        if ( !conn  )
2450            continue;
2451
2452        _crVBoxHGCMPerformPollHost(conn);
2453    }
2454#endif
2455
2456    for (i=0; i<g_crvboxhgcm.num_conns; i++)
2457    {
2458        CRConnection *conn = g_crvboxhgcm.conns[i];
2459
2460        if ( !conn )
2461            continue;
2462
2463        _crVBoxHGCMPerformReceiveMessage(conn);
2464    }
2465
2466#ifdef CHROMIUM_THREADSAFE
2467    crUnlockMutex(&g_crvboxhgcm.mutex);
2468#endif
2469
2470    VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2471
2472    return 0;
2473}
2474
2475CRConnection** crVBoxHGCMDump( int *num )
2476{
2477    *num = g_crvboxhgcm.num_conns;
2478
2479    return g_crvboxhgcm.conns;
2480}
Note: See TracBrowser for help on using the repository browser.

www.oracle.com
ContactPrivacy policyTerms of Use