VirtualBox

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

Last change on this file since 78374 was 78341, checked in by vboxsync, 6 years ago

Config.kmk,Additions/common/crOpenGL,VBox/GuestHost/OpenGL,HostServices/SharedOpenGL: Remove CHROMIUM_THREADSAFE define and apply the current default

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