VirtualBox

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

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

crOpenGL: add protocol version check(4108), add max connected clients check

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