VirtualBox

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

Last change on this file since 18111 was 18111, checked in by vboxsync, 16 years ago

crOpenGL: typo + warning if hgcm calls fail on guest side

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.2 KB
Line 
1/* $Id: vboxhgcm.c 18111 2009-03-20 11:36:45Z vboxsync $ */
2
3/** @file
4 * VBox HGCM connection
5 */
6
7/*
8 * Copyright (C) 2008 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#ifdef RT_OS_WINDOWS
24 #include <windows.h>
25 #include <ddraw.h>
26#else
27 #include <sys/ioctl.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <unistd.h>
32#endif
33
34#include "cr_error.h"
35#include "cr_net.h"
36#include "cr_bufpool.h"
37#include "cr_mem.h"
38#include "cr_string.h"
39#include "cr_endian.h"
40#include "cr_threads.h"
41#include "net_internals.h"
42
43#include <VBox/VBoxGuest.h>
44#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
45
46typedef struct {
47 int initialized;
48 int num_conns;
49 CRConnection **conns;
50 CRBufferPool *bufpool;
51#ifdef CHROMIUM_THREADSAFE
52 CRmutex mutex;
53 CRmutex recvmutex;
54#endif
55 CRNetReceiveFuncList *recv_list;
56 CRNetCloseFuncList *close_list;
57#ifdef RT_OS_WINDOWS
58 HANDLE hGuestDrv;
59 LPDIRECTDRAW pDirectDraw;
60#else
61 int iGuestDrv;
62#endif
63} CRVBOXHGCMDATA;
64
65static CRVBOXHGCMDATA g_crvboxhgcm = {0,};
66
67typedef enum {
68 CR_VBOXHGCM_USERALLOCATED,
69 CR_VBOXHGCM_MEMORY,
70 CR_VBOXHGCM_MEMORY_BIG
71#ifdef RT_OS_WINDOWS
72 ,CR_VBOXHGCM_DDRAW_SURFACE
73#endif
74} CRVBOXHGCMBUFFERKIND;
75
76#define CR_VBOXHGCM_BUFFER_MAGIC 0xABCDE321
77
78typedef struct CRVBOXHGCMBUFFER {
79 uint32_t magic;
80 CRVBOXHGCMBUFFERKIND kind;
81 uint32_t len;
82 uint32_t allocated;
83#ifdef RT_OS_WINDOWS
84 LPDIRECTDRAWSURFACE pDDS;
85#endif
86} CRVBOXHGCMBUFFER;
87
88#ifndef RT_OS_WINDOWS
89 #define TRUE true
90 #define FALSE false
91 #define INVALID_HANDLE_VALUE (-1)
92#endif
93
94/* Some forward declarations */
95static void crVBoxHGCMReceiveMessage(CRConnection *conn);
96
97#ifndef IN_GUEST
98static bool _crVBoxHGCMReadBytes(CRConnection *conn, void *buf, uint32_t len)
99{
100 CRASSERT(conn && buf);
101
102 if (!conn->pBuffer || (conn->cbBuffer<len))
103 return FALSE;
104
105 crMemcpy(buf, conn->pBuffer, len);
106
107 conn->cbBuffer -= len;
108 conn->pBuffer = conn->cbBuffer>0 ? (uint8_t*)conn->pBuffer+len : NULL;
109
110 return TRUE;
111}
112#endif
113
114/*@todo get rid of it*/
115static bool _crVBoxHGCMWriteBytes(CRConnection *conn, const void *buf, uint32_t len)
116{
117 CRASSERT(conn && buf);
118
119 /* make sure there's host buffer and it's clear */
120 CRASSERT(conn->pHostBuffer && !conn->cbHostBuffer);
121
122 if (conn->cbHostBufferAllocated < len)
123 {
124 crDebug("Host buffer too small %d out of requsted %d bytes, reallocating", conn->cbHostBufferAllocated, len);
125 crFree(conn->pHostBuffer);
126 conn->pHostBuffer = crAlloc(len);
127 if (!conn->pHostBuffer)
128 {
129 conn->cbHostBufferAllocated = 0;
130 crError("OUT_OF_MEMORY trying to allocate %d bytes", len);
131 return FALSE;
132 }
133 conn->cbHostBufferAllocated = len;
134 }
135
136 crMemcpy(conn->pHostBuffer, buf, len);
137 conn->cbHostBuffer = len;
138
139 return TRUE;
140}
141
142/**
143 * Send an HGCM request
144 *
145 * @return VBox status code
146 * @param pvData Data pointer
147 * @param cbData Data size
148 */
149/*@todo use vbglR3DoIOCtl here instead */
150static int crVBoxHGCMCall(void *pvData, unsigned cbData)
151{
152#ifdef IN_GUEST
153
154#ifdef RT_OS_WINDOWS
155 DWORD cbReturned;
156
157 if (DeviceIoControl (g_crvboxhgcm.hGuestDrv,
158 VBOXGUEST_IOCTL_HGCM_CALL(cbData),
159 pvData, cbData,
160 pvData, cbData,
161 &cbReturned,
162 NULL))
163 {
164 return VINF_SUCCESS;
165 }
166 crDebug("vboxCall failed with %x\n", GetLastError());
167 return VERR_NOT_SUPPORTED;
168#else
169 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData) >= 0)
170 {
171 return VINF_SUCCESS;
172 }
173 crWarning("vboxCall failed with %x\n", errno);
174 return VERR_NOT_SUPPORTED;
175#endif /*#ifdef RT_OS_WINDOWS*/
176
177#else /*#ifdef IN_GUEST*/
178 crError("crVBoxHGCMCall called on host side!");
179 CRASSERT(FALSE);
180 return VERR_NOT_SUPPORTED;
181#endif
182}
183
184static void *crVBoxHGCMAlloc(CRConnection *conn)
185{
186 CRVBOXHGCMBUFFER *buf;
187
188#ifdef CHROMIUM_THREADSAFE
189 crLockMutex(&g_crvboxhgcm.mutex);
190#endif
191
192 buf = (CRVBOXHGCMBUFFER *) crBufferPoolPop(g_crvboxhgcm.bufpool, conn->buffer_size);
193
194 if (!buf)
195 {
196 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
197 (void *) g_crvboxhgcm.bufpool,
198 (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
199
200#if defined(IN_GUEST) && defined(RT_OS_WINDOWS)
201 /* Try to start DDRAW on guest side */
202 if (!g_crvboxhgcm.pDirectDraw && 0)
203 {
204 HRESULT hr;
205
206 hr = DirectDrawCreate(NULL, &g_crvboxhgcm.pDirectDraw, NULL);
207 if (hr != DD_OK)
208 {
209 crWarning("Failed to create DirectDraw interface (%x)\n", hr);
210 g_crvboxhgcm.pDirectDraw = NULL;
211 }
212 else
213 {
214 hr = IDirectDraw_SetCooperativeLevel(g_crvboxhgcm.pDirectDraw, NULL, DDSCL_NORMAL);
215 if (hr != DD_OK)
216 {
217 crWarning("Failed to SetCooperativeLevel (%x)\n", hr);
218 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
219 g_crvboxhgcm.pDirectDraw = NULL;
220 }
221 crDebug("Created DirectDraw and set CooperativeLevel successfully\n");
222 }
223 }
224
225 /* Try to allocate buffer via DDRAW */
226 if (g_crvboxhgcm.pDirectDraw)
227 {
228 DDSURFACEDESC ddsd;
229 HRESULT hr;
230 LPDIRECTDRAWSURFACE lpDDS;
231
232 memset(&ddsd, 0, sizeof(ddsd));
233 ddsd.dwSize = sizeof(ddsd);
234
235 /* @todo DDSCAPS_VIDEOMEMORY ain't working for some reason
236 * also, it would be better to request dwLinearSize but it fails too
237 * ddsd.dwLinearSize = sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size;
238 */
239
240 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
241 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
242 /* use 1 byte per pixel format */
243 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
244 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
245 ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
246 ddsd.ddpfPixelFormat.dwRBitMask = 0xFF;
247 ddsd.ddpfPixelFormat.dwGBitMask = 0;
248 ddsd.ddpfPixelFormat.dwBBitMask = 0;
249 /* request given buffer size, rounded to 1k */
250 ddsd.dwWidth = 1024;
251 ddsd.dwHeight = (sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size + ddsd.dwWidth-1)/ddsd.dwWidth;
252
253 hr = IDirectDraw_CreateSurface(g_crvboxhgcm.pDirectDraw, &ddsd, &lpDDS, NULL);
254 if (hr != DD_OK)
255 {
256 crWarning("Failed to create DirectDraw surface (%x)\n", hr);
257 }
258 else
259 {
260 crDebug("Created DirectDraw surface (%x)\n", lpDDS);
261
262 hr = IDirectDrawSurface_Lock(lpDDS, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL);
263 if (hr != DD_OK)
264 {
265 crWarning("Failed to lock DirectDraw surface (%x)\n", hr);
266 IDirectDrawSurface_Release(lpDDS);
267 }
268 else
269 {
270 uint32_t cbLocked;
271 cbLocked = (ddsd.dwFlags & DDSD_LINEARSIZE) ? ddsd.dwLinearSize : ddsd.lPitch*ddsd.dwHeight;
272
273 crDebug("Locked %d bytes DirectDraw surface\n", cbLocked);
274
275 buf = (CRVBOXHGCMBUFFER *) ddsd.lpSurface;
276 CRASSERT(buf);
277 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
278 buf->kind = CR_VBOXHGCM_DDRAW_SURFACE;
279 buf->allocated = cbLocked;
280 buf->pDDS = lpDDS;
281 }
282 }
283 }
284#endif
285
286 /* We're either on host side, or we failed to allocate DDRAW buffer */
287 if (!buf)
288 {
289 crDebug("Using system malloc\n");
290 buf = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size );
291 CRASSERT(buf);
292 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
293 buf->kind = CR_VBOXHGCM_MEMORY;
294 buf->allocated = conn->buffer_size;
295#ifdef RT_OS_WINDOWS
296 buf->pDDS = NULL;
297#endif
298 }
299 }
300
301#ifdef CHROMIUM_THREADSAFE
302 crUnlockMutex(&g_crvboxhgcm.mutex);
303#endif
304
305 return (void *)( buf + 1 );
306
307}
308
309static void crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
310{
311 CRVBOXHGCMWRITE parms;
312 int rc;
313
314 parms.hdr.result = VINF_SUCCESS;
315 parms.hdr.u32ClientID = conn->u32ClientID;
316 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
317 parms.hdr.cParms = SHCRGL_CPARMS_WRITE;
318
319 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
320 parms.pBuffer.u.Pointer.size = len;
321 parms.pBuffer.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) buf;
322
323 rc = crVBoxHGCMCall(&parms, sizeof(parms));
324
325 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
326 {
327 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, parms.hdr.result);
328 }
329}
330
331static void crVBoxHGCMReadExact( CRConnection *conn, const void *buf, unsigned int len )
332{
333 CRVBOXHGCMREAD parms;
334 int rc;
335
336 parms.hdr.result = VINF_SUCCESS;
337 parms.hdr.u32ClientID = conn->u32ClientID;
338 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
339 parms.hdr.cParms = SHCRGL_CPARMS_READ;
340
341 CRASSERT(!conn->pBuffer); //make sure there's no data to process
342 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
343 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
344 parms.pBuffer.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) conn->pHostBuffer;
345
346 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
347 parms.cbBuffer.u.value32 = 0;
348
349 rc = crVBoxHGCMCall(&parms, sizeof(parms));
350
351 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
352 {
353 crWarning("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
354 return;
355 }
356
357 if (parms.cbBuffer.u.value32)
358 {
359 //conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
360 conn->pBuffer = conn->pHostBuffer;
361 conn->cbBuffer = parms.cbBuffer.u.value32;
362 }
363
364 if (conn->cbBuffer)
365 crVBoxHGCMReceiveMessage(conn);
366
367}
368
369/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
370 * This halves the number of HGCM calls we do,
371 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
372 */
373static void
374crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, CRVBOXHGCMBUFFERKIND bufferKind)
375{
376 CRVBOXHGCMWRITEREAD parms;
377 int rc;
378
379 parms.hdr.result = VINF_SUCCESS;
380 parms.hdr.u32ClientID = conn->u32ClientID;
381 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
382 parms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ;
383
384 //if (bufferKind != CR_VBOXHGCM_DDRAW_SURFACE)
385 {
386 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
387 parms.pBuffer.u.Pointer.size = len;
388 parms.pBuffer.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) buf;
389 }
390 /*else //@todo it fails badly, have to check why
391 {
392 parms.pBuffer.type = VMMDevHGCMParmType_PhysAddr;
393 parms.pBuffer.u.Pointer.size = len;
394 parms.pBuffer.u.Pointer.u.physAddr = (VMMDEVHYPPHYS32) buf;
395 }*/
396
397 CRASSERT(!conn->pBuffer); //make sure there's no data to process
398 parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out;
399 parms.pWriteback.u.Pointer.size = conn->cbHostBufferAllocated;
400 parms.pWriteback.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) conn->pHostBuffer;
401
402 parms.cbWriteback.type = VMMDevHGCMParmType_32bit;
403 parms.cbWriteback.u.value32 = 0;
404
405 rc = crVBoxHGCMCall(&parms, sizeof(parms));
406
407 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
408 {
409
410 if ((VERR_BUFFER_OVERFLOW == parms.hdr.result) && RT_SUCCESS(rc))
411 {
412 /* reallocate buffer and retry */
413
414 CRASSERT(parms.cbWriteback.u.value32>conn->cbHostBufferAllocated);
415
416 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, parms.cbWriteback.u.value32);
417
418 crFree(conn->pHostBuffer);
419 conn->cbHostBufferAllocated = parms.cbWriteback.u.value32;
420 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
421
422 crVBoxHGCMReadExact(conn, buf, len);
423
424 return;
425 }
426 else
427 {
428 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x %x\n", len, rc, parms.hdr.result);
429 return;
430 }
431 }
432
433 if (parms.cbWriteback.u.value32)
434 {
435 //conn->pBuffer = (uint8_t*) parms.pWriteback.u.Pointer.u.linearAddr;
436 conn->pBuffer = conn->pHostBuffer;
437 conn->cbBuffer = parms.cbWriteback.u.value32;
438 }
439
440 if (conn->cbBuffer)
441 crVBoxHGCMReceiveMessage(conn);
442}
443
444static void crVBoxHGCMSend(CRConnection *conn, void **bufp,
445 const void *start, unsigned int len)
446{
447 CRVBOXHGCMBUFFER *hgcm_buffer;
448
449 if (!bufp) /* We're sending a user-allocated buffer. */
450 {
451#ifndef IN_GUEST
452 //@todo remove temp buffer allocation in unpacker
453 /* we're at the host side, so just store data until guest polls us */
454 _crVBoxHGCMWriteBytes(conn, start, len);
455#else
456 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
457 crVBoxHGCMWriteReadExact(conn, start, len, CR_VBOXHGCM_USERALLOCATED);
458#endif
459 return;
460 }
461
462 /* The region [start .. start + len + 1] lies within a buffer that
463 * was allocated with crVBoxHGCMAlloc() and can be put into the free
464 * buffer pool when we're done sending it.
465 */
466
467 hgcm_buffer = (CRVBOXHGCMBUFFER *)(*bufp) - 1;
468 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
469
470 /* Length would be passed as part of HGCM pointer description
471 * No need to prepend it to the buffer
472 */
473 crVBoxHGCMWriteReadExact(conn, start, len, hgcm_buffer->kind);
474
475 /* Reclaim this pointer for reuse */
476#ifdef CHROMIUM_THREADSAFE
477 crLockMutex(&g_crvboxhgcm.mutex);
478#endif
479 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
480#ifdef CHROMIUM_THREADSAFE
481 crUnlockMutex(&g_crvboxhgcm.mutex);
482#endif
483
484 /* Since the buffer's now in the 'free' buffer pool, the caller can't
485 * use it any more. Setting bufp to NULL will make sure the caller
486 * doesn't try to re-use the buffer.
487 */
488 *bufp = NULL;
489}
490
491static void crVBoxHGCMPollHost(CRConnection *conn)
492{
493 CRVBOXHGCMREAD parms;
494 int rc;
495
496 CRASSERT(!conn->pBuffer);
497
498 parms.hdr.result = VINF_SUCCESS;
499 parms.hdr.u32ClientID = conn->u32ClientID;
500 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
501 parms.hdr.cParms = SHCRGL_CPARMS_READ;
502
503 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
504 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
505 parms.pBuffer.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) conn->pHostBuffer;
506
507 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
508 parms.cbBuffer.u.value32 = 0;
509
510 rc = crVBoxHGCMCall(&parms, sizeof(parms));
511
512 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
513 {
514 crDebug("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
515 return;
516 }
517
518 if (parms.cbBuffer.u.value32)
519 {
520 conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
521 conn->cbBuffer = parms.cbBuffer.u.value32;
522 }
523}
524
525static void crVBoxHGCMSingleRecv(CRConnection *conn, void *buf, unsigned int len)
526{
527 crVBoxHGCMReadExact(conn, buf, len);
528}
529
530static void crVBoxHGCMFree(CRConnection *conn, void *buf)
531{
532 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
533
534 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
535
536 /*@todo wrong len for redir buffers*/
537 conn->recv_credits += hgcm_buffer->len;
538
539 switch (hgcm_buffer->kind)
540 {
541 case CR_VBOXHGCM_MEMORY:
542#ifdef RT_OS_WINDOWS
543 case CR_VBOXHGCM_DDRAW_SURFACE:
544#endif
545#ifdef CHROMIUM_THREADSAFE
546 crLockMutex(&g_crvboxhgcm.mutex);
547#endif
548 if (g_crvboxhgcm.bufpool) {
549 //@todo o'rly?
550 /* pool may have been deallocated just a bit earlier in response
551 * to a SIGPIPE (Broken Pipe) signal.
552 */
553 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
554 }
555#ifdef CHROMIUM_THREADSAFE
556 crUnlockMutex(&g_crvboxhgcm.mutex);
557#endif
558 break;
559
560 case CR_VBOXHGCM_MEMORY_BIG:
561 crFree( hgcm_buffer );
562 break;
563
564 default:
565 crError( "Weird buffer kind trying to free in crVBoxHGCMFree: %d", hgcm_buffer->kind );
566 }
567}
568
569static void crVBoxHGCMReceiveMessage(CRConnection *conn)
570{
571 uint32_t len;
572 CRVBOXHGCMBUFFER *hgcm_buffer;
573 CRMessage *msg;
574 CRMessageType cached_type;
575
576 len = conn->cbBuffer;
577 CRASSERT(len > 0);
578 CRASSERT(conn->pBuffer);
579
580#ifndef IN_GUEST
581 if (conn->allow_redir_ptr)
582 {
583#endif //IN_GUEST
584 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
585
586 hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
587 hgcm_buffer->len = sizeof(CRMessageRedirPtr);
588
589 msg = (CRMessage *) (hgcm_buffer + 1);
590
591 msg->header.type = CR_MESSAGE_REDIR_PTR;
592 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
593 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
594
595 cached_type = msg->redirptr.pMessage->type;
596
597 conn->cbBuffer = 0;
598 conn->pBuffer = NULL;
599#ifndef IN_GUEST
600 }
601 else
602 {
603 if ( len <= conn->buffer_size )
604 {
605 /* put in pre-allocated buffer */
606 hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
607 }
608 else
609 {
610 /* allocate new buffer,
611 * not using pool here as it's most likely one time transfer of huge texture
612 */
613 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
614 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
615 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
616 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
617# ifdef RT_OS_WINDOWS
618 hgcm_buffer->pDDS = NULL;
619# endif
620 }
621
622 hgcm_buffer->len = len;
623
624 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
625
626 msg = (CRMessage *) (hgcm_buffer + 1);
627 cached_type = msg->header.type;
628 }
629#endif //IN_GUEST
630
631 conn->recv_credits -= len;
632 conn->total_bytes_recv += len;
633
634 crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
635
636 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
637 * OOB messages are the programmer's problem. -- Humper 12/17/01
638 */
639 if (cached_type != CR_MESSAGE_OPCODES
640 && cached_type != CR_MESSAGE_OOB
641 && cached_type != CR_MESSAGE_GATHER)
642 {
643 crVBoxHGCMFree(conn, msg);
644 }
645}
646
647/*
648 * Called on host side only, to "accept" client connection
649 */
650static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
651{
652 CRASSERT(conn && conn->pHostBuffer);
653#ifdef IN_GUEST
654 CRASSERT(FALSE);
655#endif
656}
657
658/**
659 * The function that actually connects. This should only be called by clients,
660 * guests in vbox case.
661 * Servers go through crVBoxHGCMAccept;
662 */
663/*@todo use vbglR3Something here */
664static int crVBoxHGCMDoConnect( CRConnection *conn )
665{
666#ifdef IN_GUEST
667 VBoxGuestHGCMConnectInfo info;
668
669#ifdef RT_OS_WINDOWS
670 DWORD cbReturned;
671
672 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
673 {
674 /* open VBox guest driver */
675 g_crvboxhgcm.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
676 GENERIC_READ | GENERIC_WRITE,
677 FILE_SHARE_READ | FILE_SHARE_WRITE,
678 NULL,
679 OPEN_EXISTING,
680 FILE_ATTRIBUTE_NORMAL,
681 NULL);
682
683 /* @todo check if we could rollback to softwareopengl */
684 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
685 {
686 crDebug("could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
687 return FALSE;
688 }
689 }
690#else
691 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
692 {
693 g_crvboxhgcm.iGuestDrv = open(VBOXGUEST_USER_DEVICE_NAME, O_RDWR, 0);
694 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
695 {
696 crDebug("could not open Guest Additions kernel module! rc = %d\n", errno);
697 return FALSE;
698 }
699 }
700#endif
701
702 memset (&info, 0, sizeof (info));
703 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
704 strcpy (info.Loc.u.host.achName, "VBoxSharedCrOpenGL");
705
706#ifdef RT_OS_WINDOWS
707 if (DeviceIoControl(g_crvboxhgcm.hGuestDrv,
708 VBOXGUEST_IOCTL_HGCM_CONNECT,
709 &info, sizeof (info),
710 &info, sizeof (info),
711 &cbReturned,
712 NULL))
713#else
714 /*@todo it'd fail */
715 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info)) >= 0)
716#endif
717 {
718 if (info.result == VINF_SUCCESS)
719 {
720 conn->u32ClientID = info.u32ClientID;
721 crDebug("HGCM connect was successful: client id =%x\n", conn->u32ClientID);
722 }
723 else
724 {
725 crDebug("HGCM connect failed with rc=%x\n", info.result);
726 return FALSE;
727 }
728 }
729 else
730 {
731#ifdef RT_OS_WINDOWS
732 crDebug("HGCM connect failed with rc=%x\n", GetLastError());
733#else
734 crDebug("HGCM connect failed with rc=%x\n", errno);
735#endif
736 return FALSE;
737 }
738
739 return TRUE;
740
741#else /*#ifdef IN_GUEST*/
742 crError("crVBoxHGCMDoConnect called on host side!");
743 CRASSERT(FALSE);
744 return FALSE;
745#endif
746}
747
748/*@todo same, replace DeviceIoControl with vbglR3DoIOCtl */
749static void crVBoxHGCMDoDisconnect( CRConnection *conn )
750{
751 VBoxGuestHGCMDisconnectInfo info;
752#ifdef RT_OS_WINDOWS
753 DWORD cbReturned;
754#endif
755 int i;
756
757 if (conn->pHostBuffer)
758 {
759 crFree(conn->pHostBuffer);
760 conn->pHostBuffer = NULL;
761 conn->cbHostBuffer = 0;
762 conn->cbHostBufferAllocated = 0;
763 }
764
765 conn->pBuffer = NULL;
766 conn->cbBuffer = 0;
767
768 //@todo hold lock here?
769 if (conn->type == CR_VBOXHGCM)
770 {
771 --g_crvboxhgcm.num_conns;
772
773 if (conn->index < g_crvboxhgcm.num_conns)
774 {
775 g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
776 g_crvboxhgcm.conns[conn->index]->index = conn->index;
777 }
778 else g_crvboxhgcm.conns[conn->index] = NULL;
779
780 conn->type = CR_NO_CONNECTION;
781 }
782
783#ifndef IN_GUEST
784#else
785 if (conn->u32ClientID)
786 {
787 memset (&info, 0, sizeof (info));
788 info.u32ClientID = conn->u32ClientID;
789
790#ifdef RT_OS_WINDOWS
791 if ( !DeviceIoControl(g_crvboxhgcm.hGuestDrv,
792 VBOXGUEST_IOCTL_HGCM_DISCONNECT,
793 &info, sizeof (info),
794 &info, sizeof (info),
795 &cbReturned,
796 NULL) )
797 {
798 crDebug("Disconnect failed with %x\n", GetLastError());
799 }
800#else
801 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info, sizeof (info)) < 0)
802 {
803 crDebug("Disconnect failed with %x\n", errno);
804 }
805#endif
806
807 conn->u32ClientID = 0;
808 }
809
810 /* see if any connections remain */
811 for (i = 0; i < g_crvboxhgcm.num_conns; i++)
812 if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
813 break;
814
815 /* close guest additions driver*/
816 if (i>=g_crvboxhgcm.num_conns)
817 {
818#ifdef RT_OS_WINDOWS
819 CloseHandle(g_crvboxhgcm.hGuestDrv);
820 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
821#else
822 close(g_crvboxhgcm.iGuestDrv);
823 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
824#endif
825 }
826#endif
827}
828
829static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
830{
831 crVBoxHGCMFree(conn, mess);
832 CRASSERT(FALSE);
833}
834
835static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
836{
837 CRASSERT(FALSE);
838}
839
840void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
841{
842 (void) mtu;
843
844 g_crvboxhgcm.recv_list = rfl;
845 g_crvboxhgcm.close_list = cfl;
846 if (g_crvboxhgcm.initialized)
847 {
848 return;
849 }
850
851 g_crvboxhgcm.initialized = 1;
852
853 g_crvboxhgcm.num_conns = 0;
854 g_crvboxhgcm.conns = NULL;
855
856 /* Can't open VBox guest driver here, because it gets called for host side as well */
857 /*@todo as we have 2 dll versions, can do it now.*/
858
859#ifdef RT_OS_WINDOWS
860 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
861 g_crvboxhgcm.pDirectDraw = NULL;
862#else
863 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
864#endif
865
866#ifdef CHROMIUM_THREADSAFE
867 crInitMutex(&g_crvboxhgcm.mutex);
868 crInitMutex(&g_crvboxhgcm.recvmutex);
869#endif
870 g_crvboxhgcm.bufpool = crBufferPoolInit(16);
871}
872
873/* Callback function used to free buffer pool entries */
874void crVBoxHGCMBufferFree(void *data)
875{
876#ifdef RT_OS_WINDOWS
877 LPDIRECTDRAWSURFACE lpDDS;
878#endif
879 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
880
881 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
882
883 switch (hgcm_buffer->kind)
884 {
885 case CR_VBOXHGCM_MEMORY:
886 crFree( hgcm_buffer );
887 break;
888#ifdef RT_OS_WINDOWS
889 case CR_VBOXHGCM_DDRAW_SURFACE:
890 lpDDS = hgcm_buffer->pDDS;
891 CRASSERT(lpDDS);
892 IDirectDrawSurface_Unlock(lpDDS, NULL);
893 IDirectDrawSurface_Release(lpDDS);
894 crDebug("DDraw surface freed (%x)\n", lpDDS);
895 break;
896#endif
897 case CR_VBOXHGCM_MEMORY_BIG:
898 crFree( hgcm_buffer );
899 break;
900
901 default:
902 crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
903 }
904}
905
906void crVBoxHGCMTearDown(void)
907{
908 int32_t i, cCons;
909
910 if (!g_crvboxhgcm.initialized) return;
911
912 /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
913 * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
914 * order of their connection.
915 */
916 cCons = g_crvboxhgcm.num_conns;
917 for (i=0; i<cCons; i++)
918 {
919 /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
920 crNetDisconnect(g_crvboxhgcm.conns[0]);
921 }
922 CRASSERT(0==g_crvboxhgcm.num_conns);
923
924#ifdef CHROMIUM_THREADSAFE
925 crFreeMutex(&g_crvboxhgcm.mutex);
926 crFreeMutex(&g_crvboxhgcm.recvmutex);
927#endif
928
929 if (g_crvboxhgcm.bufpool)
930 crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
931 g_crvboxhgcm.bufpool = NULL;
932
933 g_crvboxhgcm.initialized = 0;
934
935 crFree(g_crvboxhgcm.conns);
936 g_crvboxhgcm.conns = NULL;
937
938#ifdef RT_OS_WINDOWS
939 if (g_crvboxhgcm.pDirectDraw)
940 {
941 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
942 g_crvboxhgcm.pDirectDraw = NULL;
943 crDebug("DirectDraw released\n");
944 }
945#endif
946}
947
948void crVBoxHGCMConnection(CRConnection *conn)
949{
950 int i, found = 0;
951 int n_bytes;
952
953 CRASSERT(g_crvboxhgcm.initialized);
954
955 conn->type = CR_VBOXHGCM;
956 conn->Alloc = crVBoxHGCMAlloc;
957 conn->Send = crVBoxHGCMSend;
958 conn->SendExact = crVBoxHGCMWriteExact;
959 conn->Recv = crVBoxHGCMSingleRecv;
960 conn->RecvMsg = crVBoxHGCMReceiveMessage;
961 conn->Free = crVBoxHGCMFree;
962 conn->Accept = crVBoxHGCMAccept;
963 conn->Connect = crVBoxHGCMDoConnect;
964 conn->Disconnect = crVBoxHGCMDoDisconnect;
965 conn->InstantReclaim = crVBoxHGCMInstantReclaim;
966 conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
967 conn->index = g_crvboxhgcm.num_conns;
968 conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
969 conn->actual_network = 1;
970
971 conn->krecv_buf_size = 0;
972
973 conn->pBuffer = NULL;
974 conn->cbBuffer = 0;
975 conn->allow_redir_ptr = 1;
976
977 //@todo remove this crap at all later
978 conn->cbHostBufferAllocated = 2*1024;
979 conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
980 CRASSERT(conn->pHostBuffer);
981 conn->cbHostBuffer = 0;
982
983 /* Find a free slot */
984 for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
985 if (g_crvboxhgcm.conns[i] == NULL) {
986 conn->index = i;
987 g_crvboxhgcm.conns[i] = conn;
988 found = 1;
989 break;
990 }
991 }
992
993 /* Realloc connection stack if we couldn't find a free slot */
994 if (found == 0) {
995 n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
996 crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
997 g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
998 }
999}
1000
1001int crVBoxHGCMRecv(void)
1002{
1003 int32_t i;
1004
1005#ifdef IN_GUEST
1006 /* we're on guest side, poll host if it got something for us */
1007 for (i=0; i<g_crvboxhgcm.num_conns; i++)
1008 {
1009 CRConnection *conn = g_crvboxhgcm.conns[i];
1010
1011 if ( !conn || conn->type == CR_NO_CONNECTION )
1012 continue;
1013
1014 if (!conn->pBuffer)
1015 {
1016 crVBoxHGCMPollHost(conn);
1017 }
1018 }
1019#endif
1020
1021 for (i=0; i<g_crvboxhgcm.num_conns; i++)
1022 {
1023 CRConnection *conn = g_crvboxhgcm.conns[i];
1024
1025 if ( !conn || conn->type == CR_NO_CONNECTION )
1026 continue;
1027
1028 if (conn->cbBuffer>0)
1029 {
1030 crVBoxHGCMReceiveMessage(conn);
1031 }
1032 }
1033
1034 return 0;
1035}
1036
1037CRConnection** crVBoxHGCMDump( int *num )
1038{
1039 *num = g_crvboxhgcm.num_conns;
1040
1041 return g_crvboxhgcm.conns;
1042}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette