VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/net.c@ 78263

Last change on this file since 78263 was 78190, checked in by vboxsync, 6 years ago

Merge first stage of the Chromium cleanup from the branch:

  • r129818 (Remove VBOX_WITH_CR_DISPLAY_LISTS and accompanying code as it was disabled since r108676 and was never brought back (see ​bugref:3456 and ​bugref:8485))
  • r129819 (HostServices/SharedOpenGL: Remove unused main entry point from upstream server process based implementation)
  • r129820 (HostServices/SharedOpenGL: Started eliminating all backends other than HGCM. They are not used and probably wouldn't work anymore anyway)
  • r129821 (HostServices/SharedOpenGL,GuestHost/OpenGLAdditions/common/crOpenGL: Kill crTimer* API as it is not used anywhere)
  • r129822 (HostServices/SharedOpenGL,GuestHost/OpenGLAdditions/common/crOpenGL: Kill most from cr_process.h apart from two used methods)
  • r129823 (HostServices/SharedOpenGL,GuestHost/OpenGLAdditions/common/crOpenGL: Kill crList* API as it is unused)
  • r129824 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Kill crHullInteriorBox API as it is unused)
  • r129825 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Kill crWarpPoint API as it is unused)
  • r129826 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Kill CrSa* API as it is unused and not even compiled in)
  • r129827 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Kill cr_bbox.h as it is unused)
  • r129828 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove a few crParseUrl() two uses)
  • r129829 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove last crParseURL() use)
  • r129830 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove crParseURL())
  • r129831 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove VBOX_WITH_COCOA_QT and related code when not set as it is the default for years now and we don't support anything else anymore)
  • r129832 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove unused cr_logo.h)
  • r129833 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove unused crut_api.h and crut_clientapi.h)
  • r129834 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove unused cr_dmx.h)
  • r129835 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove unused cr_perf.h)
  • r129836 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove cr_rand.h and friends as it is not actively used anywhere)
  • r129837 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of all the swapped versions in the packer SPU, we never change endianess from guest to host and don't need it)
  • r129838 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove more swapper versions in the packer related code)
  • r129839 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove more swapper versions in the packer related code)
  • r129840 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove unused pack_pica.c)
  • r129841 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove more swapper versions in the packer related code)
  • r129842 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of cr_endianess.h and friends)
  • r129843 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of unused lowercase.py)
  • r129844 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of unused cr_calllists.h and friends)
  • r129845 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of completely unused idpool.c, not even compiled in)
  • r129846 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of unused cr_debugopcodes.h and friends)
  • r129847 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Make the cr_mem.h API inline and get rid of the implementation in the util library)
  • r129848 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of SPUOptions and related code as it is of no use for us)
  • r129849 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of cr_environment.h and friends and convert usage to RTEnv* APIs)
  • r129850 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of unused renderspu_agl.c)
  • r129851 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Remove unused code in cr_htable.h)
  • r129853 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Introduce a state paremeter for the unpacker workers instead of reyling on global variables, work in progress)
  • r129854 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Let the caller of crUnpack set up the initial state. This allows to get rid of the global return_ptr and writeback_ptr as they get supplied in the unpacker state by the server)
  • r129855 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of the cr_lastDispatch and cr_unpackDispatch as they are of no use now)
  • r129856 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Get rid of the global cr_unpackData and cr_unpackDataEnd symbols by indtroducing another hack to make it possible for certail server dispatch callbacks to access the data buffer)
  • r129857 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: build fix for release builds)
  • r129858 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Make the pointer to the unpacker state non const (is required for the access verification))
  • r129859 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: First iteration of the buffer size validation to prevent out of bound read access + added todos for places where additional checks are needed)
  • r129860 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Working on remaining verification todos)
  • r129861 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Working on remaining verification todos)
  • r129871 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Working on remaining verification todos)
  • r129872 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Stop as soon as the unpacker encountered an error)
  • r129876 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Working on remaining verification todos)
  • r129880 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Working on remaining verification todos)
  • r129882 (HostServices/SharedOpenGL,GuestHost/OpenGL,Additions/common/crOpenGL: Fixed some offsets in unpack_texture.c, 3DMark03 renders correctly again)
  • r130013 (HostServices/SharedOpenGL: Convert files to C++ so we can use C99 featuers on Windows with cl.exe)
  • r130014 (HostServices/SharedOpenGL,GuestHost/OpenGL: WIndows build fixes)
  • r130015 (HostServices/SharedOpenGL,GuestHost/OpenGL: More Windows build fixes)
  • r130036 (Config.kmk: Fix linker error on Windows by temporarily disabling the use of VBoxGuestR3DllMinW2K)
  • r130094 (src/VBox/GuestHost/OpenGL: Revert inlining the allocation/free functions in R3 completely as it doesn't work on Windows if memory is allocated and freed across different DLLs which don't share a common CRT, causes crashes in RtlValidtaeHeap())
  • r130095 (src/VBox/GuestHost/OpenGL,src/VBox/Additions/common/crOpenGL/pack: Don't use floating point specifiers in packspu_GetString() to avoid R6002 errors (couldn't fully understand why they occur suddenly after the rework but this gets rid of it))
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.7 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdarg.h>
10#include <errno.h>
11#include <memory.h>
12#include <signal.h>
13
14#ifdef WINDOWS
15#define WIN32_LEAN_AND_MEAN
16#include <process.h>
17#else
18#include <unistd.h>
19#endif
20
21#include "cr_mem.h"
22#include "cr_error.h"
23#include "cr_string.h"
24#include "cr_net.h"
25#include "cr_netserver.h"
26#include "cr_pixeldata.h"
27#include "cr_bufpool.h"
28#include "cr_threads.h"
29#include "net_internals.h"
30
31
32#define CR_MINIMUM_MTU 1024
33
34#define CR_INITIAL_RECV_CREDITS ( 1 << 21 ) /* 2MB */
35
36/* Allow up to four processes per node. . . */
37#define CR_QUADRICS_LOWEST_RANK 0
38#define CR_QUADRICS_HIGHEST_RANK 3
39
40static struct {
41 int initialized; /* flag */
42 CRNetReceiveFuncList *recv_list; /* what to do with arriving packets */
43 CRNetCloseFuncList *close_list; /* what to do when a client goes down */
44
45 /* Number of connections using each type of interface: */
46 int use_hgcm;
47
48 int num_clients; /* total number of clients (unused?) */
49
50#ifdef CHROMIUM_THREADSAFE
51 CRmutex mutex;
52#endif
53} cr_net;
54
55
56
57/**
58 * Helper routine used by both crNetConnectToServer() and crNetAcceptClient().
59 * Call the protocol-specific Init() and Connection() functions.
60 *
61 */
62static void
63InitConnection(CRConnection *conn
64#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
65 , struct VBOXUHGSMI *pHgsmi
66#endif
67 )
68{
69#ifdef VBOX_WITH_HGCM
70 cr_net.use_hgcm++;
71 crVBoxHGCMInit(cr_net.recv_list, cr_net.close_list);
72 crVBoxHGCMConnection(conn
73#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
74 , pHgsmi
75#endif
76 );
77#endif
78}
79
80
81
82/**
83 * Establish a connection with a server.
84 * \param server the server to connect to, in the form
85 * "protocol://servername:port" where the port specifier
86 * is optional and if the protocol is missing it is assumed
87 * to be "tcpip".
88 * \param default_port the port to connect to, if port not specified in the
89 * server URL string.
90 * \param mtu desired maximum transmission unit size (in bytes)
91 * \param broker either 1 or 0 to indicate if connection is brokered through
92 * the mothership
93 */
94CRConnection * crNetConnectToServer( const char *server, int mtu, int broker
95#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
96 , struct VBOXUHGSMI *pHgsmi
97#endif
98)
99{
100 CRConnection *conn;
101
102 crDebug( "In crNetConnectToServer( \"%s\", mtu=%d, broker=%d )",
103 server, mtu, broker );
104
105 CRASSERT( cr_net.initialized );
106
107 if (mtu < CR_MINIMUM_MTU)
108 {
109 crError( "You tried to connect to server \"%s\" with an mtu of %d, "
110 "but the minimum MTU is %d", server, mtu, CR_MINIMUM_MTU );
111 }
112
113 conn = (CRConnection *) crCalloc( sizeof(*conn) );
114 if (!conn)
115 return NULL;
116
117 /* init the non-zero fields */
118 conn->type = CR_NO_CONNECTION; /* we don't know yet */
119 conn->recv_credits = CR_INITIAL_RECV_CREDITS;
120 conn->mtu = mtu;
121 conn->buffer_size = mtu;
122 conn->broker = broker;
123
124 crInitMessageList(&conn->messageList);
125
126 /* now, just dispatch to the appropriate protocol's initialization functions. */
127 InitConnection(conn
128#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
129 , pHgsmi
130#endif
131 );
132
133 if (!crNetConnect( conn ))
134 {
135 crDebug("crNetConnectToServer() failed, freeing the connection");
136 #ifdef CHROMIUM_THREADSAFE
137 crFreeMutex( &conn->messageList.lock );
138 #endif
139 conn->Disconnect(conn);
140 crFree( conn );
141 return NULL;
142 }
143
144 crDebug( "Done connecting to %s (swapping=%d)", server, conn->swap );
145 return conn;
146}
147
148/**
149 * Send a message to the receiver that another connection is needed.
150 * We send a CR_MESSAGE_NEWCLIENT packet, then call crNetServerConnect.
151 */
152void crNetNewClient( CRNetServer *ns
153#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
154 , struct VBOXUHGSMI *pHgsmi
155#endif
156)
157{
158 crNetServerConnect( ns
159#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
160 , pHgsmi
161#endif
162);
163}
164
165
166/**
167 * Accept a connection from a client.
168 * \param protocol the protocol to use (such as "tcpip" or "gm")
169 * \param hostname optional hostname of the expected client (may be NULL)
170 * \param port number of the port to accept on
171 * \param mtu maximum transmission unit
172 * \param broker either 1 or 0 to indicate if connection is brokered through
173 * the mothership
174 * \return new CRConnection object, or NULL
175 */
176CRConnection *
177crNetAcceptClient( const char *protocol, const char *hostname,
178 unsigned short port, unsigned int mtu, int broker )
179{
180 CRConnection *conn;
181
182 RT_NOREF(hostname);
183 CRASSERT( cr_net.initialized );
184
185 conn = (CRConnection *) crCalloc( sizeof( *conn ) );
186 if (!conn)
187 return NULL;
188
189 /* init the non-zero fields */
190 conn->type = CR_NO_CONNECTION; /* we don't know yet */
191 conn->recv_credits = CR_INITIAL_RECV_CREDITS;
192 conn->mtu = mtu;
193 conn->buffer_size = mtu;
194 conn->broker = broker;
195
196 crInitMessageList(&conn->messageList);
197
198 /* now, just dispatch to the appropriate protocol's initialization functions. */
199 crDebug("In crNetAcceptClient( protocol=\"%s\" port=%d mtu=%d )",
200 protocol, (int) port, (int) mtu);
201
202 /* call the protocol-specific init routines */
203 InitConnection(conn
204#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
205 , NULL
206#endif
207 );
208
209 crNetAccept(conn);
210 return conn;
211}
212
213
214/**
215 * Close and free given connection.
216 */
217void
218crNetFreeConnection(CRConnection *conn)
219{
220 conn->Disconnect(conn);
221 #ifdef CHROMIUM_THREADSAFE
222 crFreeMutex( &conn->messageList.lock );
223 #endif
224 crFree(conn);
225}
226
227
228/**
229 * Start the ball rolling. give functions to handle incoming traffic
230 * (usually placing blocks on a queue), and a handler for dropped
231 * connections.
232 */
233void crNetInit( CRNetReceiveFunc recvFunc, CRNetCloseFunc closeFunc )
234{
235 CRNetReceiveFuncList *rfl;
236 CRNetCloseFuncList *cfl;
237
238 if ( cr_net.initialized )
239 {
240 /*crDebug( "Networking already initialized!" );*/
241 }
242 else
243 {
244 cr_net.use_hgcm = 0;
245 cr_net.num_clients = 0;
246#ifdef CHROMIUM_THREADSAFE
247 crInitMutex(&cr_net.mutex);
248#endif
249
250 cr_net.initialized = 1;
251 cr_net.recv_list = NULL;
252 cr_net.close_list = NULL;
253 }
254
255 if (recvFunc != NULL)
256 {
257 /* check if function is already in the list */
258 for (rfl = cr_net.recv_list ; rfl ; rfl = rfl->next )
259 {
260 if (rfl->recv == recvFunc)
261 {
262 /* we've already seen this function -- do nothing */
263 break;
264 }
265 }
266 /* not in list, so insert at the head */
267 if (!rfl)
268 {
269 rfl = (CRNetReceiveFuncList *) crAlloc( sizeof (*rfl ));
270 rfl->recv = recvFunc;
271 rfl->next = cr_net.recv_list;
272 cr_net.recv_list = rfl;
273 }
274 }
275
276 if (closeFunc != NULL)
277 {
278 /* check if function is already in the list */
279 for (cfl = cr_net.close_list ; cfl ; cfl = cfl->next )
280 {
281 if (cfl->close == closeFunc)
282 {
283 /* we've already seen this function -- do nothing */
284 break;
285 }
286 }
287 /* not in list, so insert at the head */
288 if (!cfl)
289 {
290 cfl = (CRNetCloseFuncList *) crAlloc( sizeof (*cfl ));
291 cfl->close = closeFunc;
292 cfl->next = cr_net.close_list;
293 cr_net.close_list = cfl;
294 }
295 }
296}
297
298/* Free up stuff */
299void crNetTearDown(void)
300{
301 CRNetReceiveFuncList *rfl;
302 CRNetCloseFuncList *cfl;
303 void *tmp;
304
305 if (!cr_net.initialized) return;
306
307#ifdef CHROMIUM_THREADSAFE
308 crLockMutex(&cr_net.mutex);
309#endif
310
311 /* Note, other protocols used by chromium should free up stuff too,
312 * but VBox doesn't use them, so no other checks.
313 */
314 if (cr_net.use_hgcm)
315 crVBoxHGCMTearDown();
316
317 for (rfl = cr_net.recv_list ; rfl ; rfl = (CRNetReceiveFuncList *) tmp )
318 {
319 tmp = rfl->next;
320 crFree(rfl);
321 }
322
323 for (cfl = cr_net.close_list ; cfl ; cfl = (CRNetCloseFuncList *) tmp )
324 {
325 tmp = cfl->next;
326 crFree(cfl);
327 }
328
329 cr_net.initialized = 0;
330
331#ifdef CHROMIUM_THREADSAFE
332 crUnlockMutex(&cr_net.mutex);
333 crFreeMutex(&cr_net.mutex);
334#endif
335}
336
337CRConnection** crNetDump( int* num )
338{
339 CRConnection **c;
340
341#ifdef VBOX_WITH_HGCM
342 c = crVBoxHGCMDump( num );
343 if ( c ) return c;
344#endif
345
346 *num = 0;
347 return NULL;
348}
349
350
351/*
352 * Allocate a network data buffer. The size will be the mtu size specified
353 * earlier to crNetConnectToServer() or crNetAcceptClient().
354 *
355 * Buffers that will eventually be transmitted on a connection
356 * *must* be allocated using this interface. This way, we can
357 * automatically pin memory and tag blocks, and we can also use
358 * our own buffer pool management.
359 */
360void *crNetAlloc( CRConnection *conn )
361{
362 CRASSERT( conn );
363 return conn->Alloc( conn );
364}
365
366
367/**
368 * This returns a buffer (which was obtained from crNetAlloc()) back
369 * to the network layer so that it may be reused.
370 */
371void crNetFree( CRConnection *conn, void *buf )
372{
373 conn->Free( conn, buf );
374}
375
376
377void
378crInitMessageList(CRMessageList *list)
379{
380 list->head = list->tail = NULL;
381 list->numMessages = 0;
382#ifdef CHROMIUM_THREADSAFE
383 crInitMutex(&list->lock);
384 crInitCondition(&list->nonEmpty);
385#endif
386}
387
388
389/**
390 * Add a message node to the end of the message list.
391 * \param list the message list
392 * \param msg points to start of message buffer
393 * \param len length of message, in bytes
394 * \param conn connection associated with message (may be NULL)
395 */
396void
397crEnqueueMessage(CRMessageList *list, CRMessage *msg, unsigned int len,
398 CRConnection *conn)
399{
400 CRMessageListNode *node;
401
402#ifdef CHROMIUM_THREADSAFE
403 crLockMutex(&list->lock);
404#endif
405
406 node = (CRMessageListNode *) crAlloc(sizeof(CRMessageListNode));
407 node->mesg = msg;
408 node->len = len;
409 node->conn = conn;
410 node->next = NULL;
411
412 /* insert at tail */
413 if (list->tail)
414 list->tail->next = node;
415 else
416 list->head = node;
417 list->tail = node;
418
419 list->numMessages++;
420
421#ifdef CHROMIUM_THREADSAFE
422 crSignalCondition(&list->nonEmpty);
423 crUnlockMutex(&list->lock);
424#endif
425}
426
427
428/**
429 * Remove first message node from message list and return it.
430 * Don't block.
431 * \return 1 if message was dequeued, 0 otherwise.
432 */
433static int
434crDequeueMessageNoBlock(CRMessageList *list, CRMessage **msg,
435 unsigned int *len, CRConnection **conn)
436{
437 int retval;
438
439#ifdef CHROMIUM_THREADSAFE
440 crLockMutex(&list->lock);
441#endif
442
443 if (list->head) {
444 CRMessageListNode *node = list->head;
445
446 /* unlink the node */
447 list->head = node->next;
448 if (!list->head) {
449 /* empty list */
450 list->tail = NULL;
451 }
452
453 *msg = node->mesg;
454 *len = node->len;
455 if (conn)
456 *conn = node->conn;
457
458 list->numMessages--;
459
460 crFree(node);
461 retval = 1;
462 }
463 else {
464 *msg = NULL;
465 *len = 0;
466 retval = 0;
467 }
468
469#ifdef CHROMIUM_THREADSAFE
470 crUnlockMutex(&list->lock);
471#endif
472
473 return retval;
474}
475
476
477/**
478 * Remove message from tail of list. Block until non-empty if needed.
479 * \param list the message list
480 * \param msg returns start of message
481 * \param len returns message length, in bytes
482 * \param conn returns connection associated with message (may be NULL)
483 */
484void
485crDequeueMessage(CRMessageList *list, CRMessage **msg, unsigned int *len,
486 CRConnection **conn)
487{
488 CRMessageListNode *node;
489
490#ifdef CHROMIUM_THREADSAFE
491 crLockMutex(&list->lock);
492#endif
493
494#ifdef CHROMIUM_THREADSAFE
495 while (!list->head) {
496 crWaitCondition(&list->nonEmpty, &list->lock);
497 }
498#else
499 CRASSERT(list->head);
500#endif
501
502 node = list->head;
503
504 /* unlink the node */
505 list->head = node->next;
506 if (!list->head) {
507 /* empty list */
508 list->tail = NULL;
509 }
510
511 *msg = node->mesg;
512 CRASSERT((*msg)->header.type);
513 *len = node->len;
514 if (conn)
515 *conn = node->conn;
516
517 list->numMessages--;
518
519 crFree(node);
520
521#ifdef CHROMIUM_THREADSAFE
522 crUnlockMutex(&list->lock);
523#endif
524}
525
526
527
528/**
529 * Send a set of commands on a connection. Pretty straightforward, just
530 * error checking, byte counting, and a dispatch to the protocol's
531 * "send" implementation.
532 * The payload will be prefixed by a 4-byte length field.
533 *
534 * \param conn the network connection
535 * \param bufp if non-null the buffer was provided by the network layer
536 * and will be returned to the 'free' pool after it's sent.
537 * \param start points to first byte to send, which must point to a CRMessage
538 * object!
539 * \param len number of bytes to send
540 */
541void
542crNetSend(CRConnection *conn, void **bufp, const void *start, unsigned int len)
543{
544 CRMessage *msg = (CRMessage *) start;
545
546 CRASSERT( conn );
547 CRASSERT( len > 0 );
548 if ( bufp ) {
549 /* The region from [start .. start + len - 1] must lie inside the
550 * buffer pointed to by *bufp.
551 */
552 CRASSERT( start >= *bufp );
553 CRASSERT( (unsigned char *) start + len <=
554 (unsigned char *) *bufp + conn->buffer_size );
555 }
556
557#ifdef DEBUG
558 if ( conn->send_credits > CR_INITIAL_RECV_CREDITS )
559 {
560 crError( "crNetSend: send_credits=%u, looks like there is a leak (max=%u)",
561 conn->send_credits, CR_INITIAL_RECV_CREDITS );
562 }
563#endif
564
565 conn->total_bytes_sent += len;
566
567 msg->header.conn_id = conn->id;
568 conn->Send( conn, bufp, start, len );
569}
570
571
572/**
573 * Like crNetSend(), but the network layer is free to discard the data
574 * if something goes wrong. In particular, the UDP layer might discard
575 * the data in the event of transmission errors.
576 */
577void crNetBarf( CRConnection *conn, void **bufp,
578 const void *start, unsigned int len )
579{
580 CRMessage *msg = (CRMessage *) start;
581 CRASSERT( conn );
582 CRASSERT( len > 0 );
583 CRASSERT( conn->Barf );
584 if ( bufp ) {
585 CRASSERT( start >= *bufp );
586 CRASSERT( (unsigned char *) start + len <=
587 (unsigned char *) *bufp + conn->buffer_size );
588 }
589
590#ifdef DEBUG
591 if ( conn->send_credits > CR_INITIAL_RECV_CREDITS )
592 {
593 crError( "crNetBarf: send_credits=%u, looks like there is a "
594 "leak (max=%u)", conn->send_credits,
595 CR_INITIAL_RECV_CREDITS );
596 }
597#endif
598
599 conn->total_bytes_sent += len;
600
601 msg->header.conn_id = conn->id;
602 conn->Barf( conn, bufp, start, len );
603}
604
605
606/**
607 * Send a block of bytes across the connection without any sort of
608 * header/length information.
609 * \param conn the network connection
610 * \param buf points to first byte to send
611 * \param len number of bytes to send
612 */
613void crNetSendExact( CRConnection *conn, const void *buf, unsigned int len )
614{
615 CRASSERT(conn->SendExact);
616 conn->SendExact( conn, buf, len );
617}
618
619
620/**
621 * Connect to a server, as specified by the 'name' and 'buffer_size' fields
622 * of the CRNetServer parameter.
623 * When done, the CrNetServer's conn field will be initialized.
624 */
625void crNetServerConnect( CRNetServer *ns
626#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
627 , struct VBOXUHGSMI *pHgsmi
628#endif
629)
630{
631 ns->conn = crNetConnectToServer( ns->name,
632 ns->buffer_size, 0
633#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
634 , pHgsmi
635#endif
636 );
637}
638
639/**
640 * Actually set up the specified connection.
641 * Apparently, this is only called from the crNetConnectToServer function.
642 */
643int crNetConnect( CRConnection *conn )
644{
645 return conn->Connect( conn );
646}
647
648
649/**
650 * Tear down a network connection (close the socket, etc).
651 */
652void crNetDisconnect( CRConnection *conn )
653{
654 conn->Disconnect( conn );
655#ifdef CHROMIUM_THREADSAFE
656 crFreeMutex( &conn->messageList.lock );
657#endif
658 crFree( conn );
659}
660
661
662/**
663 * Actually set up the specified connection.
664 * Apparently, this is only called from the crNetConnectToServer function.
665 */
666void crNetAccept( CRConnection *conn)
667{
668 conn->Accept( conn);
669}
670
671
672/**
673 * Do a blocking receive on a particular connection. This only
674 * really works for TCPIP, but it's really only used (right now) by
675 * the mothership client library.
676 * Read exactly the number of bytes specified (no headers/prefixes).
677 */
678void crNetSingleRecv( CRConnection *conn, void *buf, unsigned int len )
679{
680 /** @todo Remove after users have been identified and eliminated .*/
681 crError( "Can't do a crNetSingleReceive on anything other than TCPIP." );
682 conn->Recv( conn, buf, len );
683}
684
685
686/**
687 * Receive a chunk of a CR_MESSAGE_MULTI_BODY/TAIL transmission.
688 * \param conn the network connection
689 * \param msg the incoming multi-part message
690 * \param len number of bytes in the message
691 */
692static void
693crNetRecvMulti( CRConnection *conn, CRMessageMulti *msg, unsigned int len )
694{
695 CRMultiBuffer *multi = &(conn->multi);
696 unsigned char *src, *dst;
697
698 CRASSERT( len > sizeof(*msg) );
699 len -= sizeof(*msg);
700
701 /* Check if there's enough room in the multi-buffer to append 'len' bytes */
702 if ( len + multi->len > multi->max )
703 {
704 if ( multi->max == 0 )
705 {
706 multi->len = conn->sizeof_buffer_header;
707 multi->max = 8192; /* arbitrary initial size */
708 }
709 /* grow the buffer by 2x until it's big enough */
710 while ( len + multi->len > multi->max )
711 {
712 multi->max <<= 1;
713 }
714 crRealloc( &multi->buf, multi->max );
715 }
716
717 dst = (unsigned char *) multi->buf + multi->len;
718 src = (unsigned char *) msg + sizeof(*msg);
719 crMemcpy( dst, src, len );
720 multi->len += len;
721
722 if (msg->header.type == CR_MESSAGE_MULTI_TAIL)
723 {
724 /* OK, we've collected the last chunk of the multi-part message */
725 conn->HandleNewMessage(
726 conn,
727 (CRMessage *) (((char *) multi->buf) + conn->sizeof_buffer_header),
728 multi->len - conn->sizeof_buffer_header );
729
730 /* clean this up before calling the user */
731 multi->buf = NULL;
732 multi->len = 0;
733 multi->max = 0;
734 }
735
736 /* Don't do this too early! */
737 conn->InstantReclaim( conn, (CRMessage *) msg );
738}
739
740
741/**
742 * Increment the connection's send_credits by msg->credits.
743 */
744static void
745crNetRecvFlowControl( CRConnection *conn, CRMessageFlowControl *msg,
746 unsigned int len )
747{
748 CRASSERT( len == sizeof(CRMessageFlowControl) );
749 conn->send_credits += msg->credits;
750 conn->InstantReclaim( conn, (CRMessage *) msg );
751}
752
753#ifdef IN_GUEST
754/**
755 * Called by the main receive function when we get a CR_MESSAGE_WRITEBACK
756 * message. Writeback is used to implement glGet*() functions.
757 */
758static void
759crNetRecvWriteback( CRMessageWriteback *wb )
760{
761 int *writeback;
762 crMemcpy( &writeback, &(wb->writeback_ptr), sizeof( writeback ) );
763 (*writeback)--;
764}
765
766
767/**
768 * Called by the main receive function when we get a CR_MESSAGE_READBACK
769 * message. Used to implement glGet*() functions.
770 */
771static void
772crNetRecvReadback( CRMessageReadback *rb, unsigned int len )
773{
774 /* minus the header, the destination pointer,
775 * *and* the implicit writeback pointer at the head. */
776
777 int payload_len = len - sizeof( *rb );
778 int *writeback;
779 void *dest_ptr;
780 crMemcpy( &writeback, &(rb->writeback_ptr), sizeof( writeback ) );
781 crMemcpy( &dest_ptr, &(rb->readback_ptr), sizeof( dest_ptr ) );
782
783 (*writeback)--;
784 crMemcpy( dest_ptr, ((char *)rb) + sizeof(*rb), payload_len );
785}
786#endif
787
788/**
789 * This is used by the SPUs that do packing (such as Pack, Tilesort and
790 * Replicate) to process ReadPixels messages. We can't call this directly
791 * from the message loop below because the SPU's have other housekeeping
792 * to do for ReadPixels (such as decrementing counters).
793 */
794void
795crNetRecvReadPixels( const CRMessageReadPixels *rp, unsigned int len )
796{
797 int payload_len = len - sizeof( *rp );
798 char *dest_ptr;
799 const char *src_ptr = (const char *) rp + sizeof(*rp);
800
801 /* set dest_ptr value */
802 crMemcpy( &(dest_ptr), &(rp->pixels), sizeof(dest_ptr));
803
804 /* store pixel data in app's memory */
805 if (rp->alignment == 1 &&
806 rp->skipRows == 0 &&
807 rp->skipPixels == 0 &&
808 (rp->rowLength == 0 || rp->rowLength == rp->width)) {
809 /* no special packing is needed */
810 crMemcpy( dest_ptr, src_ptr, payload_len );
811 }
812 else {
813 /* need special packing */
814 CRPixelPackState packing;
815 packing.skipRows = rp->skipRows;
816 packing.skipPixels = rp->skipPixels;
817 packing.alignment = rp->alignment;
818 packing.rowLength = rp->rowLength;
819 packing.imageHeight = 0;
820 packing.skipImages = 0;
821 packing.swapBytes = GL_FALSE;
822 packing.psLSBFirst = GL_FALSE;
823 crPixelCopy2D( rp->width, rp->height,
824 dest_ptr, rp->format, rp->type, &packing,
825 src_ptr, rp->format, rp->type, /*unpacking*/NULL);
826 }
827}
828
829
830
831/**
832 * If an incoming message is not consumed by any of the connection's
833 * receive callbacks, this function will get called.
834 *
835 * XXX Make this function static???
836 */
837void
838crNetDefaultRecv( CRConnection *conn, CRMessage *msg, unsigned int len )
839{
840 CRMessage *pRealMsg;
841
842 pRealMsg = (msg->header.type!=CR_MESSAGE_REDIR_PTR) ? msg : (CRMessage*) msg->redirptr.pMessage;
843
844 switch (pRealMsg->header.type)
845 {
846 case CR_MESSAGE_GATHER:
847 break;
848 case CR_MESSAGE_MULTI_BODY:
849 case CR_MESSAGE_MULTI_TAIL:
850 crNetRecvMulti( conn, &(pRealMsg->multi), len );
851 return;
852 case CR_MESSAGE_FLOW_CONTROL:
853 crNetRecvFlowControl( conn, &(pRealMsg->flowControl), len );
854 return;
855 case CR_MESSAGE_OPCODES:
856 case CR_MESSAGE_OOB:
857 break;
858 case CR_MESSAGE_READ_PIXELS:
859 WARN(( "Can't handle read pixels" ));
860 return;
861 case CR_MESSAGE_WRITEBACK:
862#ifdef IN_GUEST
863 crNetRecvWriteback( &(pRealMsg->writeback) );
864#else
865 WARN(("CR_MESSAGE_WRITEBACK not expected\n"));
866#endif
867 return;
868 case CR_MESSAGE_READBACK:
869#ifdef IN_GUEST
870 crNetRecvReadback( &(pRealMsg->readback), len );
871#else
872 WARN(("CR_MESSAGE_READBACK not expected\n"));
873#endif
874 return;
875 case CR_MESSAGE_CRUT:
876 /* nothing */
877 break;
878 default:
879 /* We can end up here if anything strange happens in
880 * the GM layer. In particular, if the user tries to
881 * send unpinned memory over GM it gets sent as all
882 * 0xAA instead. This can happen when a program exits
883 * ungracefully, so the GM is still DMAing memory as
884 * it is disappearing out from under it. We can also
885 * end up here if somebody adds a message type, and
886 * doesn't put it in the above case block. That has
887 * an obvious fix. */
888 {
889 char string[128];
890 crBytesToString( string, sizeof(string), msg, len );
891 WARN(("crNetDefaultRecv: received a bad message: type=%d buf=[%s]\n"
892 "Did you add a new message type and forget to tell "
893 "crNetDefaultRecv() about it?\n",
894 msg->header.type, string ));
895 }
896 }
897
898 /* If we make it this far, it's not a special message, so append it to
899 * the end of the connection's list of received messages.
900 */
901 crEnqueueMessage(&conn->messageList, msg, len, conn);
902}
903
904
905/**
906 * Default handler for receiving data. Called via crNetRecv().
907 * Typically, the various implementations of the network layer call this.
908 * \param msg this is the address of the message (of <len> bytes) the
909 * first part of which is a CRMessage union.
910 */
911void
912crNetDispatchMessage( CRNetReceiveFuncList *rfl, CRConnection *conn,
913 CRMessage *msg, unsigned int len )
914{
915 for ( ; rfl ; rfl = rfl->next)
916 {
917 if (rfl->recv( conn, msg, len ))
918 {
919 /* Message was consumed by somebody (maybe a SPU).
920 * All done.
921 */
922 return;
923 }
924 }
925 /* Append the message to the connection's message list. It'll be
926 * consumed later (by crNetPeekMessage or crNetGetMessage and
927 * then freed with a call to crNetFree()). At this point, the buffer
928 * *must* have been allocated with crNetAlloc!
929 */
930 crNetDefaultRecv( conn, msg, len );
931}
932
933
934/**
935 * Return number of messages queued up on the given connection.
936 */
937int
938crNetNumMessages(CRConnection *conn)
939{
940 return conn->messageList.numMessages;
941}
942
943
944/**
945 * Get the next message in the connection's message list. These are
946 * message that have already been received. We do not try to read more
947 * bytes from the network connection.
948 *
949 * The crNetFree() function should be called when finished with the message!
950 *
951 * \param conn the network connection
952 * \param message returns a pointer to the next message
953 * \return length of message (header + payload, in bytes)
954 */
955unsigned int
956crNetPeekMessage( CRConnection *conn, CRMessage **message )
957{
958 unsigned int len;
959 CRConnection *dummyConn = NULL;
960 if (crDequeueMessageNoBlock(&conn->messageList, message, &len, &dummyConn))
961 return len;
962 else
963 return 0;
964}
965
966
967/**
968 * Get the next message from the given network connection. If there isn't
969 * one already in the linked list of received messages, call crNetRecv()
970 * until we get something.
971 *
972 * \param message returns pointer to the message
973 * \return total length of message (header + payload, in bytes)
974 */
975unsigned int
976crNetGetMessage( CRConnection *conn, CRMessage **message )
977{
978 /* Keep getting work to do */
979 for (;;)
980 {
981 int len = crNetPeekMessage( conn, message );
982 if (len)
983 return len;
984 crNetRecv(
985#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
986 conn
987#endif
988 );
989 }
990
991#if !defined(WINDOWS) && !defined(IRIX) && !defined(IRIX64)
992 /* silence compiler */
993 return 0;
994#endif
995}
996
997
998/**
999 * Read a \n-terminated string from a connection. Replace the \n with \0.
1000 * Useful for reading from the mothership.
1001 * \note This is an extremely inefficient way to read a string!
1002 *
1003 * \param conn the network connection
1004 * \param buf buffer in which to place results
1005 */
1006void crNetReadline( CRConnection *conn, void *buf )
1007{
1008 RT_NOREF(buf);
1009
1010 if (!conn || conn->type == CR_NO_CONNECTION)
1011 return;
1012
1013 /** @todo Remove after users have been found and eliminated. */
1014 crError( "Can't do a crNetReadline on anything other than TCPIP (%d).",conn->type );
1015}
1016
1017#ifdef IN_GUEST
1018uint32_t crNetHostCapsGet(void)
1019{
1020#ifdef VBOX_WITH_HGCM
1021 if ( cr_net.use_hgcm )
1022 return crVBoxHGCMHostCapsGet();
1023#endif
1024 WARN(("HostCaps supportted for HGCM only!"));
1025 return 0;
1026}
1027#endif
1028
1029/**
1030 * The big boy -- call this function to see (non-blocking) if there is
1031 * any pending work. If there is, the networking layer's "work received"
1032 * handler will be called, so this function only returns a flag. Work
1033 * is assumed to be placed on queues for processing by the handler.
1034 */
1035int crNetRecv(
1036#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1037 CRConnection *conn
1038#else
1039 void
1040#endif
1041 )
1042{
1043 int found_work = 0;
1044
1045#ifdef VBOX_WITH_HGCM
1046 if ( cr_net.use_hgcm )
1047 found_work += crVBoxHGCMRecv(
1048#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1049 conn
1050#endif
1051 );
1052#endif
1053
1054 return found_work;
1055}
1056
Note: See TracBrowser for help on using the repository browser.

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