VirtualBox

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

Last change on this file since 50984 was 50984, checked in by vboxsync, 11 years ago

crOpenGL: command blocks: enable in guest if host supports it; bugfixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 37.0 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_url.h"
25#include "cr_net.h"
26#include "cr_netserver.h"
27#include "cr_pixeldata.h"
28#include "cr_environment.h"
29#include "cr_endian.h"
30#include "cr_bufpool.h"
31#include "cr_threads.h"
32#include "net_internals.h"
33
34
35#define CR_MINIMUM_MTU 1024
36
37#define CR_INITIAL_RECV_CREDITS ( 1 << 21 ) /* 2MB */
38
39/* Allow up to four processes per node. . . */
40#define CR_QUADRICS_LOWEST_RANK 0
41#define CR_QUADRICS_HIGHEST_RANK 3
42
43static struct {
44 int initialized; /* flag */
45 CRNetReceiveFuncList *recv_list; /* what to do with arriving packets */
46 CRNetCloseFuncList *close_list; /* what to do when a client goes down */
47
48 /* Number of connections using each type of interface: */
49 int use_tcpip;
50 int use_ib;
51 int use_file;
52 int use_udp;
53 int use_gm;
54 int use_sdp;
55 int use_teac;
56 int use_tcscomm;
57 int use_hgcm;
58
59 int num_clients; /* total number of clients (unused?) */
60
61#ifdef CHROMIUM_THREADSAFE
62 CRmutex mutex;
63#endif
64 int my_rank; /* Teac/TSComm only */
65} cr_net;
66
67
68
69/**
70 * Helper routine used by both crNetConnectToServer() and crNetAcceptClient().
71 * Call the protocol-specific Init() and Connection() functions.
72 *
73 */
74static void
75InitConnection(CRConnection *conn, const char *protocol, unsigned int mtu
76#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
77 , struct VBOXUHGSMI *pHgsmi
78#endif
79 )
80{
81 if (!crStrcmp(protocol, "devnull"))
82 {
83 crDevnullInit(cr_net.recv_list, cr_net.close_list, mtu);
84 crDevnullConnection(conn);
85 }
86 else if (!crStrcmp(protocol, "file"))
87 {
88 cr_net.use_file++;
89 crFileInit(cr_net.recv_list, cr_net.close_list, mtu);
90 crFileConnection(conn);
91 }
92 else if (!crStrcmp(protocol, "swapfile"))
93 {
94 /* file with byte-swapping */
95 cr_net.use_file++;
96 crFileInit(cr_net.recv_list, cr_net.close_list, mtu);
97 crFileConnection(conn);
98 conn->swap = 1;
99 }
100 else if (!crStrcmp(protocol, "tcpip"))
101 {
102 cr_net.use_tcpip++;
103 crTCPIPInit(cr_net.recv_list, cr_net.close_list, mtu);
104 crTCPIPConnection(conn);
105 }
106 else if (!crStrcmp(protocol, "udptcpip"))
107 {
108 cr_net.use_udp++;
109 crUDPTCPIPInit(cr_net.recv_list, cr_net.close_list, mtu);
110 crUDPTCPIPConnection(conn);
111 }
112#ifdef VBOX_WITH_HGCM
113 else if (!crStrcmp(protocol, "vboxhgcm"))
114 {
115 cr_net.use_hgcm++;
116 crVBoxHGCMInit(cr_net.recv_list, cr_net.close_list, mtu);
117 crVBoxHGCMConnection(conn
118#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
119 , pHgsmi
120#endif
121 );
122 }
123#endif
124#ifdef GM_SUPPORT
125 else if (!crStrcmp(protocol, "gm"))
126 {
127 cr_net.use_gm++;
128 crGmInit(cr_net.recv_list, cr_net.close_list, mtu);
129 crGmConnection(conn);
130 }
131#endif
132#ifdef TEAC_SUPPORT
133 else if (!crStrcmp(protocol, "quadrics"))
134 {
135 cr_net.use_teac++;
136 crTeacInit(cr_net.recv_list, cr_net.close_list, mtu);
137 crTeacConnection(conn);
138 }
139#endif
140#ifdef TCSCOMM_SUPPORT
141 else if (!crStrcmp(protocol, "quadrics-tcscomm"))
142 {
143 cr_net.use_tcscomm++;
144 crTcscommInit(cr_net.recv_list, cr_net.close_list, mtu);
145 crTcscommConnection(conn);
146 }
147#endif
148#ifdef SDP_SUPPORT
149 else if (!crStrcmp(protocol, "sdp"))
150 {
151 cr_net.use_sdp++;
152 crSDPInit(cr_net.recv_list, cr_net.close_list, mtu);
153 crSDPConnection(conn);
154 }
155#endif
156#ifdef IB_SUPPORT
157 else if (!crStrcmp(protocol, "ib"))
158 {
159 cr_net.use_ib++;
160 crDebug("Calling crIBInit()");
161 crIBInit(cr_net.recv_list, cr_net.close_list, mtu);
162 crIBConnection(conn);
163 crDebug("Done Calling crIBInit()");
164 }
165#endif
166#ifdef HP_MULTICAST_SUPPORT
167 else if (!crStrcmp(protocol, "hpmc"))
168 {
169 cr_net.use_hpmc++;
170 crHPMCInit(cr_net.recv_list, cr_net.close_list, mtu);
171 crHPMCConnection(conn);
172 }
173#endif
174 else
175 {
176 crError("Unknown protocol: \"%s\"", protocol);
177 }
178}
179
180
181
182/**
183 * Establish a connection with a server.
184 * \param server the server to connect to, in the form
185 * "protocol://servername:port" where the port specifier
186 * is optional and if the protocol is missing it is assumed
187 * to be "tcpip".
188 * \param default_port the port to connect to, if port not specified in the
189 * server URL string.
190 * \param mtu desired maximum transmission unit size (in bytes)
191 * \param broker either 1 or 0 to indicate if connection is brokered through
192 * the mothership
193 */
194CRConnection * crNetConnectToServer( const char *server, unsigned short default_port, int mtu, int broker
195#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
196 , struct VBOXUHGSMI *pHgsmi
197#endif
198)
199{
200 char hostname[4096], protocol[4096];
201 unsigned short port;
202 CRConnection *conn;
203
204 crDebug( "In crNetConnectToServer( \"%s\", port=%d, mtu=%d, broker=%d )",
205 server, default_port, mtu, broker );
206
207 CRASSERT( cr_net.initialized );
208
209 if (mtu < CR_MINIMUM_MTU)
210 {
211 crError( "You tried to connect to server \"%s\" with an mtu of %d, "
212 "but the minimum MTU is %d", server, mtu, CR_MINIMUM_MTU );
213 }
214
215 /* Tear the URL apart into relevant portions. */
216 if ( !crParseURL( server, protocol, hostname, &port, default_port ) ) {
217 crError( "Malformed URL: \"%s\"", server );
218 }
219
220 /* If the host name is "localhost" replace it with the _real_ name
221 * of the localhost. If we don't do this, there seems to be
222 * confusion in the mothership as to whether or not "localhost" and
223 * "foo.bar.com" are the same machine.
224 */
225 if (crStrcmp(hostname, "localhost") == 0) {
226 int rv = crGetHostname(hostname, 4096);
227 CRASSERT(rv == 0);
228 (void) rv;
229 }
230
231 /* XXX why is this here??? I think it could be moved into the
232 * crTeacConnection() function with no problem. I.e. change the
233 * connection's port, teac_rank and tcscomm_rank there. (BrianP)
234 */
235 if ( !crStrcmp( protocol, "quadrics" ) ||
236 !crStrcmp( protocol, "quadrics-tcscomm" ) ) {
237 /* For Quadrics protocols, treat "port" as "rank" */
238 if ( port > CR_QUADRICS_HIGHEST_RANK ) {
239 crWarning( "Invalid crserver rank, %d, defaulting to %d\n",
240 port, CR_QUADRICS_LOWEST_RANK );
241 port = CR_QUADRICS_LOWEST_RANK;
242 }
243 }
244 crDebug( "Connecting to %s on port %d, with protocol %s",
245 hostname, port, protocol );
246
247#ifdef SDP_SUPPORT
248 /* This makes me ill, but we need to "fix" the hostname for sdp. MCH */
249 if (!crStrcmp(protocol, "sdp")) {
250 char* temp;
251 temp = strtok(hostname, ".");
252 crStrcat(temp, crGetSDPHostnameSuffix());
253 crStrcpy(hostname, temp);
254 crDebug("SDP rename hostname: %s", hostname);
255 }
256#endif
257
258 conn = (CRConnection *) crCalloc( sizeof(*conn) );
259 if (!conn)
260 return NULL;
261
262 /* init the non-zero fields */
263 conn->type = CR_NO_CONNECTION; /* we don't know yet */
264 conn->recv_credits = CR_INITIAL_RECV_CREDITS;
265 conn->hostname = crStrdup( hostname );
266 conn->port = port;
267 conn->mtu = mtu;
268 conn->buffer_size = mtu;
269 conn->broker = broker;
270 conn->endianness = crDetermineEndianness();
271 /* XXX why are these here??? Move them into the crTeacConnection()
272 * and crTcscommConnection() functions.
273 */
274 conn->teac_id = -1;
275 conn->teac_rank = port;
276 conn->tcscomm_id = -1;
277 conn->tcscomm_rank = port;
278
279 crInitMessageList(&conn->messageList);
280
281 /* now, just dispatch to the appropriate protocol's initialization functions. */
282 InitConnection(conn, protocol, mtu
283#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
284 , pHgsmi
285#endif
286 );
287
288 if (!crNetConnect( conn ))
289 {
290 crDebug("crNetConnectToServer() failed, freeing the connection");
291 #ifdef CHROMIUM_THREADSAFE
292 crFreeMutex( &conn->messageList.lock );
293 #endif
294 conn->Disconnect(conn);
295 crFree( conn );
296 return NULL;
297 }
298
299 crDebug( "Done connecting to %s (swapping=%d)", server, conn->swap );
300 return conn;
301}
302
303/**
304 * Send a message to the receiver that another connection is needed.
305 * We send a CR_MESSAGE_NEWCLIENT packet, then call crNetServerConnect.
306 */
307void crNetNewClient( CRNetServer *ns
308#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
309 , struct VBOXUHGSMI *pHgsmi
310#endif
311)
312{
313 /*
314 unsigned int len = sizeof(CRMessageNewClient);
315 CRMessageNewClient msg;
316
317 CRASSERT( conn );
318
319 if (conn->swap)
320 msg.header.type = (CRMessageType) SWAP32(CR_MESSAGE_NEWCLIENT);
321 else
322 msg.header.type = CR_MESSAGE_NEWCLIENT;
323
324 crNetSend( conn, NULL, &msg, len );
325 */
326
327 crNetServerConnect( ns
328#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
329 , pHgsmi
330#endif
331);
332}
333
334
335/**
336 * Accept a connection from a client.
337 * \param protocol the protocol to use (such as "tcpip" or "gm")
338 * \param hostname optional hostname of the expected client (may be NULL)
339 * \param port number of the port to accept on
340 * \param mtu maximum transmission unit
341 * \param broker either 1 or 0 to indicate if connection is brokered through
342 * the mothership
343 * \return new CRConnection object, or NULL
344 */
345CRConnection *
346crNetAcceptClient( const char *protocol, const char *hostname,
347 unsigned short port, unsigned int mtu, int broker )
348{
349 CRConnection *conn;
350
351 CRASSERT( cr_net.initialized );
352
353 conn = (CRConnection *) crCalloc( sizeof( *conn ) );
354 if (!conn)
355 return NULL;
356
357 /* init the non-zero fields */
358 conn->type = CR_NO_CONNECTION; /* we don't know yet */
359 conn->recv_credits = CR_INITIAL_RECV_CREDITS;
360 conn->port = port;
361 conn->mtu = mtu;
362 conn->buffer_size = mtu;
363 conn->broker = broker;
364 conn->endianness = crDetermineEndianness();
365 conn->teac_id = -1;
366 conn->teac_rank = -1;
367 conn->tcscomm_id = -1;
368 conn->tcscomm_rank = -1;
369
370 crInitMessageList(&conn->messageList);
371
372 /* now, just dispatch to the appropriate protocol's initialization functions. */
373 crDebug("In crNetAcceptClient( protocol=\"%s\" port=%d mtu=%d )",
374 protocol, (int) port, (int) mtu);
375
376 /* special case */
377 if ( !crStrncmp( protocol, "file", crStrlen( "file" ) ) ||
378 !crStrncmp( protocol, "swapfile", crStrlen( "swapfile" ) ) )
379 {
380 char filename[4096];
381 char protocol_only[4096];
382
383 cr_net.use_file++;
384 if (!crParseURL(protocol, protocol_only, filename, NULL, 0))
385 {
386 crError( "Malformed URL: \"%s\"", protocol );
387 }
388 conn->hostname = crStrdup( filename );
389
390 /* call the protocol-specific init routines */ // ktd (add)
391 InitConnection(conn, protocol_only, mtu
392#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
393 , NULL
394#endif
395 ); // ktd (add)
396 }
397 else {
398 /* call the protocol-specific init routines */
399 InitConnection(conn, protocol, mtu
400#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
401 , NULL
402#endif
403 );
404 }
405
406 crNetAccept( conn, hostname, port );
407 return conn;
408}
409
410
411/**
412 * Close and free given connection.
413 */
414void
415crNetFreeConnection(CRConnection *conn)
416{
417 conn->Disconnect(conn);
418 crFree( conn->hostname );
419 #ifdef CHROMIUM_THREADSAFE
420 crFreeMutex( &conn->messageList.lock );
421 #endif
422 crFree(conn);
423}
424
425
426extern void __getHostInfo();
427/**
428 * Start the ball rolling. give functions to handle incoming traffic
429 * (usually placing blocks on a queue), and a handler for dropped
430 * connections.
431 */
432void crNetInit( CRNetReceiveFunc recvFunc, CRNetCloseFunc closeFunc )
433{
434 CRNetReceiveFuncList *rfl;
435 CRNetCloseFuncList *cfl;
436
437 if ( cr_net.initialized )
438 {
439 /*crDebug( "Networking already initialized!" );*/
440 }
441 else
442 {
443#ifdef WINDOWS
444 /* @todo: do we actually need that WSA stuff with VBox at all? */
445 WORD wVersionRequested = MAKEWORD(2, 0);
446 WSADATA wsaData;
447 int err;
448
449 err = WSAStartup(wVersionRequested, &wsaData);
450 if (err != 0)
451 crError("Couldn't initialize sockets on WINDOWS");
452 //reinit hostname for debug messages as it's incorrect before WSAStartup gets called
453 __getHostInfo();
454#endif
455
456 cr_net.use_gm = 0;
457 cr_net.use_udp = 0;
458 cr_net.use_tcpip = 0;
459 cr_net.use_sdp = 0;
460 cr_net.use_tcscomm = 0;
461 cr_net.use_teac = 0;
462 cr_net.use_file = 0;
463 cr_net.use_hgcm = 0;
464 cr_net.num_clients = 0;
465#ifdef CHROMIUM_THREADSAFE
466 crInitMutex(&cr_net.mutex);
467#endif
468
469 cr_net.initialized = 1;
470 cr_net.recv_list = NULL;
471 cr_net.close_list = NULL;
472 }
473
474 if (recvFunc != NULL)
475 {
476 /* check if function is already in the list */
477 for (rfl = cr_net.recv_list ; rfl ; rfl = rfl->next )
478 {
479 if (rfl->recv == recvFunc)
480 {
481 /* we've already seen this function -- do nothing */
482 break;
483 }
484 }
485 /* not in list, so insert at the head */
486 if (!rfl)
487 {
488 rfl = (CRNetReceiveFuncList *) crAlloc( sizeof (*rfl ));
489 rfl->recv = recvFunc;
490 rfl->next = cr_net.recv_list;
491 cr_net.recv_list = rfl;
492 }
493 }
494
495 if (closeFunc != NULL)
496 {
497 /* check if function is already in the list */
498 for (cfl = cr_net.close_list ; cfl ; cfl = cfl->next )
499 {
500 if (cfl->close == closeFunc)
501 {
502 /* we've already seen this function -- do nothing */
503 break;
504 }
505 }
506 /* not in list, so insert at the head */
507 if (!cfl)
508 {
509 cfl = (CRNetCloseFuncList *) crAlloc( sizeof (*cfl ));
510 cfl->close = closeFunc;
511 cfl->next = cr_net.close_list;
512 cr_net.close_list = cfl;
513 }
514 }
515}
516
517/* Free up stuff */
518void crNetTearDown()
519{
520 CRNetReceiveFuncList *rfl;
521 CRNetCloseFuncList *cfl;
522 void *tmp;
523
524 if (!cr_net.initialized) return;
525
526#ifdef CHROMIUM_THREADSAFE
527 crLockMutex(&cr_net.mutex);
528#endif
529
530 /* Note, other protocols used by chromium should free up stuff too,
531 * but VBox doesn't use them, so no other checks.
532 */
533 if (cr_net.use_hgcm)
534 crVBoxHGCMTearDown();
535
536 for (rfl = cr_net.recv_list ; rfl ; rfl = (CRNetReceiveFuncList *) tmp )
537 {
538 tmp = rfl->next;
539 crFree(rfl);
540 }
541
542 for (cfl = cr_net.close_list ; cfl ; cfl = (CRNetCloseFuncList *) tmp )
543 {
544 tmp = cfl->next;
545 crFree(cfl);
546 }
547
548 cr_net.initialized = 0;
549
550#ifdef CHROMIUM_THREADSAFE
551 crUnlockMutex(&cr_net.mutex);
552 crFreeMutex(&cr_net.mutex);
553#endif
554}
555
556CRConnection** crNetDump( int* num )
557{
558 CRConnection **c;
559
560 c = crTCPIPDump( num );
561 if ( c ) return c;
562
563 c = crDevnullDump( num );
564 if ( c ) return c;
565
566 c = crFileDump( num );
567 if ( c ) return c;
568
569#ifdef VBOX_WITH_HGCM
570 c = crVBoxHGCMDump( num );
571 if ( c ) return c;
572#endif
573#ifdef GM_SUPPORT
574 c = crGmDump( num );
575 if ( c ) return c;
576#endif
577#ifdef IB_SUPPORT
578 c = crIBDump( num );
579 if ( c ) return c;
580#endif
581#ifdef SDP_SUPPORT
582 c = crSDPDump( num );
583 if ( c ) return c;
584#endif
585
586 *num = 0;
587 return NULL;
588}
589
590
591/*
592 * Allocate a network data buffer. The size will be the mtu size specified
593 * earlier to crNetConnectToServer() or crNetAcceptClient().
594 *
595 * Buffers that will eventually be transmitted on a connection
596 * *must* be allocated using this interface. This way, we can
597 * automatically pin memory and tag blocks, and we can also use
598 * our own buffer pool management.
599 */
600void *crNetAlloc( CRConnection *conn )
601{
602 CRASSERT( conn );
603 return conn->Alloc( conn );
604}
605
606
607/**
608 * This returns a buffer (which was obtained from crNetAlloc()) back
609 * to the network layer so that it may be reused.
610 */
611void crNetFree( CRConnection *conn, void *buf )
612{
613 conn->Free( conn, buf );
614}
615
616
617void
618crInitMessageList(CRMessageList *list)
619{
620 list->head = list->tail = NULL;
621 list->numMessages = 0;
622#ifdef CHROMIUM_THREADSAFE
623 crInitMutex(&list->lock);
624 crInitCondition(&list->nonEmpty);
625#endif
626}
627
628
629/**
630 * Add a message node to the end of the message list.
631 * \param list the message list
632 * \param msg points to start of message buffer
633 * \param len length of message, in bytes
634 * \param conn connection associated with message (may be NULL)
635 */
636void
637crEnqueueMessage(CRMessageList *list, CRMessage *msg, unsigned int len,
638 CRConnection *conn)
639{
640 CRMessageListNode *node;
641
642#ifdef CHROMIUM_THREADSAFE
643 crLockMutex(&list->lock);
644#endif
645
646 node = (CRMessageListNode *) crAlloc(sizeof(CRMessageListNode));
647 node->mesg = msg;
648 node->len = len;
649 node->conn = conn;
650 node->next = NULL;
651
652 /* insert at tail */
653 if (list->tail)
654 list->tail->next = node;
655 else
656 list->head = node;
657 list->tail = node;
658
659 list->numMessages++;
660
661#ifdef CHROMIUM_THREADSAFE
662 crSignalCondition(&list->nonEmpty);
663 crUnlockMutex(&list->lock);
664#endif
665}
666
667
668/**
669 * Remove first message node from message list and return it.
670 * Don't block.
671 * \return 1 if message was dequeued, 0 otherwise.
672 */
673static int
674crDequeueMessageNoBlock(CRMessageList *list, CRMessage **msg,
675 unsigned int *len, CRConnection **conn)
676{
677 int retval;
678
679#ifdef CHROMIUM_THREADSAFE
680 crLockMutex(&list->lock);
681#endif
682
683 if (list->head) {
684 CRMessageListNode *node = list->head;
685
686 /* unlink the node */
687 list->head = node->next;
688 if (!list->head) {
689 /* empty list */
690 list->tail = NULL;
691 }
692
693 *msg = node->mesg;
694 *len = node->len;
695 if (conn)
696 *conn = node->conn;
697
698 list->numMessages--;
699
700 crFree(node);
701 retval = 1;
702 }
703 else {
704 *msg = NULL;
705 *len = 0;
706 retval = 0;
707 }
708
709#ifdef CHROMIUM_THREADSAFE
710 crUnlockMutex(&list->lock);
711#endif
712
713 return retval;
714}
715
716
717/**
718 * Remove message from tail of list. Block until non-empty if needed.
719 * \param list the message list
720 * \param msg returns start of message
721 * \param len returns message length, in bytes
722 * \param conn returns connection associated with message (may be NULL)
723 */
724void
725crDequeueMessage(CRMessageList *list, CRMessage **msg, unsigned int *len,
726 CRConnection **conn)
727{
728 CRMessageListNode *node;
729
730#ifdef CHROMIUM_THREADSAFE
731 crLockMutex(&list->lock);
732#endif
733
734#ifdef CHROMIUM_THREADSAFE
735 while (!list->head) {
736 crWaitCondition(&list->nonEmpty, &list->lock);
737 }
738#else
739 CRASSERT(list->head);
740#endif
741
742 node = list->head;
743
744 /* unlink the node */
745 list->head = node->next;
746 if (!list->head) {
747 /* empty list */
748 list->tail = NULL;
749 }
750
751 *msg = node->mesg;
752 CRASSERT((*msg)->header.type);
753 *len = node->len;
754 if (conn)
755 *conn = node->conn;
756
757 list->numMessages--;
758
759 crFree(node);
760
761#ifdef CHROMIUM_THREADSAFE
762 crUnlockMutex(&list->lock);
763#endif
764}
765
766
767
768/**
769 * Send a set of commands on a connection. Pretty straightforward, just
770 * error checking, byte counting, and a dispatch to the protocol's
771 * "send" implementation.
772 * The payload will be prefixed by a 4-byte length field.
773 *
774 * \param conn the network connection
775 * \param bufp if non-null the buffer was provided by the network layer
776 * and will be returned to the 'free' pool after it's sent.
777 * \param start points to first byte to send, which must point to a CRMessage
778 * object!
779 * \param len number of bytes to send
780 */
781void
782crNetSend(CRConnection *conn, void **bufp, const void *start, unsigned int len)
783{
784 CRMessage *msg = (CRMessage *) start;
785
786 CRASSERT( conn );
787 CRASSERT( len > 0 );
788 if ( bufp ) {
789 /* The region from [start .. start + len - 1] must lie inside the
790 * buffer pointed to by *bufp.
791 */
792 CRASSERT( start >= *bufp );
793 CRASSERT( (unsigned char *) start + len <=
794 (unsigned char *) *bufp + conn->buffer_size );
795 }
796
797#ifdef DEBUG
798 if ( conn->send_credits > CR_INITIAL_RECV_CREDITS )
799 {
800 crError( "crNetSend: send_credits=%u, looks like there is a leak (max=%u)",
801 conn->send_credits, CR_INITIAL_RECV_CREDITS );
802 }
803#endif
804
805 conn->total_bytes_sent += len;
806
807 msg->header.conn_id = conn->id;
808 conn->Send( conn, bufp, start, len );
809}
810
811
812/**
813 * Like crNetSend(), but the network layer is free to discard the data
814 * if something goes wrong. In particular, the UDP layer might discard
815 * the data in the event of transmission errors.
816 */
817void crNetBarf( CRConnection *conn, void **bufp,
818 const void *start, unsigned int len )
819{
820 CRMessage *msg = (CRMessage *) start;
821 CRASSERT( conn );
822 CRASSERT( len > 0 );
823 CRASSERT( conn->Barf );
824 if ( bufp ) {
825 CRASSERT( start >= *bufp );
826 CRASSERT( (unsigned char *) start + len <=
827 (unsigned char *) *bufp + conn->buffer_size );
828 }
829
830#ifdef DEBUG
831 if ( conn->send_credits > CR_INITIAL_RECV_CREDITS )
832 {
833 crError( "crNetBarf: send_credits=%u, looks like there is a "
834 "leak (max=%u)", conn->send_credits,
835 CR_INITIAL_RECV_CREDITS );
836 }
837#endif
838
839 conn->total_bytes_sent += len;
840
841 msg->header.conn_id = conn->id;
842 conn->Barf( conn, bufp, start, len );
843}
844
845
846/**
847 * Send a block of bytes across the connection without any sort of
848 * header/length information.
849 * \param conn the network connection
850 * \param buf points to first byte to send
851 * \param len number of bytes to send
852 */
853void crNetSendExact( CRConnection *conn, const void *buf, unsigned int len )
854{
855 CRASSERT(conn->SendExact);
856 conn->SendExact( conn, buf, len );
857}
858
859
860/**
861 * Connect to a server, as specified by the 'name' and 'buffer_size' fields
862 * of the CRNetServer parameter.
863 * When done, the CrNetServer's conn field will be initialized.
864 */
865void crNetServerConnect( CRNetServer *ns
866#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
867 , struct VBOXUHGSMI *pHgsmi
868#endif
869)
870{
871 ns->conn = crNetConnectToServer( ns->name, DEFAULT_SERVER_PORT,
872 ns->buffer_size, 0
873#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
874 , pHgsmi
875#endif
876 );
877}
878
879/**
880 * Actually set up the specified connection.
881 * Apparently, this is only called from the crNetConnectToServer function.
882 */
883int crNetConnect( CRConnection *conn )
884{
885 return conn->Connect( conn );
886}
887
888
889/**
890 * Tear down a network connection (close the socket, etc).
891 */
892void crNetDisconnect( CRConnection *conn )
893{
894 conn->Disconnect( conn );
895 crFree( conn->hostname );
896#ifdef CHROMIUM_THREADSAFE
897 crFreeMutex( &conn->messageList.lock );
898#endif
899 crFree( conn );
900}
901
902
903/**
904 * Actually set up the specified connection.
905 * Apparently, this is only called from the crNetConnectToServer function.
906 */
907void crNetAccept( CRConnection *conn, const char *hostname, unsigned short port )
908{
909 conn->Accept( conn, hostname, port );
910}
911
912
913/**
914 * Do a blocking receive on a particular connection. This only
915 * really works for TCPIP, but it's really only used (right now) by
916 * the mothership client library.
917 * Read exactly the number of bytes specified (no headers/prefixes).
918 */
919void crNetSingleRecv( CRConnection *conn, void *buf, unsigned int len )
920{
921 if (conn->type != CR_TCPIP)
922 {
923 crError( "Can't do a crNetSingleReceive on anything other than TCPIP." );
924 }
925 conn->Recv( conn, buf, len );
926}
927
928
929/**
930 * Receive a chunk of a CR_MESSAGE_MULTI_BODY/TAIL transmission.
931 * \param conn the network connection
932 * \param msg the incoming multi-part message
933 * \param len number of bytes in the message
934 */
935static void
936crNetRecvMulti( CRConnection *conn, CRMessageMulti *msg, unsigned int len )
937{
938 CRMultiBuffer *multi = &(conn->multi);
939 unsigned char *src, *dst;
940
941 CRASSERT( len > sizeof(*msg) );
942 len -= sizeof(*msg);
943
944 /* Check if there's enough room in the multi-buffer to append 'len' bytes */
945 if ( len + multi->len > multi->max )
946 {
947 if ( multi->max == 0 )
948 {
949 multi->len = conn->sizeof_buffer_header;
950 multi->max = 8192; /* arbitrary initial size */
951 }
952 /* grow the buffer by 2x until it's big enough */
953 while ( len + multi->len > multi->max )
954 {
955 multi->max <<= 1;
956 }
957 crRealloc( &multi->buf, multi->max );
958 }
959
960 dst = (unsigned char *) multi->buf + multi->len;
961 src = (unsigned char *) msg + sizeof(*msg);
962 crMemcpy( dst, src, len );
963 multi->len += len;
964
965 if (msg->header.type == CR_MESSAGE_MULTI_TAIL)
966 {
967 /* OK, we've collected the last chunk of the multi-part message */
968 conn->HandleNewMessage(
969 conn,
970 (CRMessage *) (((char *) multi->buf) + conn->sizeof_buffer_header),
971 multi->len - conn->sizeof_buffer_header );
972
973 /* clean this up before calling the user */
974 multi->buf = NULL;
975 multi->len = 0;
976 multi->max = 0;
977 }
978
979 /* Don't do this too early! */
980 conn->InstantReclaim( conn, (CRMessage *) msg );
981}
982
983
984/**
985 * Increment the connection's send_credits by msg->credits.
986 */
987static void
988crNetRecvFlowControl( CRConnection *conn, CRMessageFlowControl *msg,
989 unsigned int len )
990{
991 CRASSERT( len == sizeof(CRMessageFlowControl) );
992 conn->send_credits += (conn->swap ? SWAP32(msg->credits) : msg->credits);
993 conn->InstantReclaim( conn, (CRMessage *) msg );
994}
995
996#ifdef IN_GUEST
997/**
998 * Called by the main receive function when we get a CR_MESSAGE_WRITEBACK
999 * message. Writeback is used to implement glGet*() functions.
1000 */
1001static void
1002crNetRecvWriteback( CRMessageWriteback *wb )
1003{
1004 int *writeback;
1005 crMemcpy( &writeback, &(wb->writeback_ptr), sizeof( writeback ) );
1006 (*writeback)--;
1007}
1008
1009
1010/**
1011 * Called by the main receive function when we get a CR_MESSAGE_READBACK
1012 * message. Used to implement glGet*() functions.
1013 */
1014static void
1015crNetRecvReadback( CRMessageReadback *rb, unsigned int len )
1016{
1017 /* minus the header, the destination pointer,
1018 * *and* the implicit writeback pointer at the head. */
1019
1020 int payload_len = len - sizeof( *rb );
1021 int *writeback;
1022 void *dest_ptr;
1023 crMemcpy( &writeback, &(rb->writeback_ptr), sizeof( writeback ) );
1024 crMemcpy( &dest_ptr, &(rb->readback_ptr), sizeof( dest_ptr ) );
1025
1026 (*writeback)--;
1027 crMemcpy( dest_ptr, ((char *)rb) + sizeof(*rb), payload_len );
1028}
1029#endif
1030
1031/**
1032 * This is used by the SPUs that do packing (such as Pack, Tilesort and
1033 * Replicate) to process ReadPixels messages. We can't call this directly
1034 * from the message loop below because the SPU's have other housekeeping
1035 * to do for ReadPixels (such as decrementing counters).
1036 */
1037void
1038crNetRecvReadPixels( const CRMessageReadPixels *rp, unsigned int len )
1039{
1040 int payload_len = len - sizeof( *rp );
1041 char *dest_ptr;
1042 const char *src_ptr = (const char *) rp + sizeof(*rp);
1043
1044 /* set dest_ptr value */
1045 crMemcpy( &(dest_ptr), &(rp->pixels), sizeof(dest_ptr));
1046
1047 /* store pixel data in app's memory */
1048 if (rp->alignment == 1 &&
1049 rp->skipRows == 0 &&
1050 rp->skipPixels == 0 &&
1051 (rp->rowLength == 0 || rp->rowLength == rp->width)) {
1052 /* no special packing is needed */
1053 crMemcpy( dest_ptr, src_ptr, payload_len );
1054 }
1055 else {
1056 /* need special packing */
1057 CRPixelPackState packing;
1058 packing.skipRows = rp->skipRows;
1059 packing.skipPixels = rp->skipPixels;
1060 packing.alignment = rp->alignment;
1061 packing.rowLength = rp->rowLength;
1062 packing.imageHeight = 0;
1063 packing.skipImages = 0;
1064 packing.swapBytes = GL_FALSE;
1065 packing.psLSBFirst = GL_FALSE;
1066 crPixelCopy2D( rp->width, rp->height,
1067 dest_ptr, rp->format, rp->type, &packing,
1068 src_ptr, rp->format, rp->type, /*unpacking*/NULL);
1069 }
1070}
1071
1072
1073
1074/**
1075 * If an incoming message is not consumed by any of the connection's
1076 * receive callbacks, this function will get called.
1077 *
1078 * XXX Make this function static???
1079 */
1080void
1081crNetDefaultRecv( CRConnection *conn, CRMessage *msg, unsigned int len )
1082{
1083 CRMessage *pRealMsg;
1084
1085 pRealMsg = (msg->header.type!=CR_MESSAGE_REDIR_PTR) ? msg : (CRMessage*) msg->redirptr.pMessage;
1086
1087 switch (pRealMsg->header.type)
1088 {
1089 case CR_MESSAGE_GATHER:
1090 break;
1091 case CR_MESSAGE_MULTI_BODY:
1092 case CR_MESSAGE_MULTI_TAIL:
1093 crNetRecvMulti( conn, &(pRealMsg->multi), len );
1094 return;
1095 case CR_MESSAGE_FLOW_CONTROL:
1096 crNetRecvFlowControl( conn, &(pRealMsg->flowControl), len );
1097 return;
1098 case CR_MESSAGE_OPCODES:
1099 case CR_MESSAGE_OOB:
1100 {
1101 /*CRMessageOpcodes *ops = (CRMessageOpcodes *) msg;
1102 *unsigned char *data_ptr = (unsigned char *) ops + sizeof( *ops) + ((ops->numOpcodes + 3 ) & ~0x03);
1103 *crDebugOpcodes( stdout, data_ptr-1, ops->numOpcodes ); */
1104 }
1105 break;
1106 case CR_MESSAGE_READ_PIXELS:
1107 WARN(( "Can't handle read pixels" ));
1108 return;
1109 case CR_MESSAGE_WRITEBACK:
1110#ifdef IN_GUEST
1111 crNetRecvWriteback( &(pRealMsg->writeback) );
1112#else
1113 WARN(("CR_MESSAGE_WRITEBACK not expected\n"));
1114#endif
1115 return;
1116 case CR_MESSAGE_READBACK:
1117#ifdef IN_GUEST
1118 crNetRecvReadback( &(pRealMsg->readback), len );
1119#else
1120 WARN(("CR_MESSAGE_READBACK not expected\n"));
1121#endif
1122 return;
1123 case CR_MESSAGE_CRUT:
1124 /* nothing */
1125 break;
1126 default:
1127 /* We can end up here if anything strange happens in
1128 * the GM layer. In particular, if the user tries to
1129 * send unpinned memory over GM it gets sent as all
1130 * 0xAA instead. This can happen when a program exits
1131 * ungracefully, so the GM is still DMAing memory as
1132 * it is disappearing out from under it. We can also
1133 * end up here if somebody adds a message type, and
1134 * doesn't put it in the above case block. That has
1135 * an obvious fix. */
1136 {
1137 char string[128];
1138 crBytesToString( string, sizeof(string), msg, len );
1139 WARN(("crNetDefaultRecv: received a bad message: type=%d buf=[%s]\n"
1140 "Did you add a new message type and forget to tell "
1141 "crNetDefaultRecv() about it?\n",
1142 msg->header.type, string ));
1143 }
1144 }
1145
1146 /* If we make it this far, it's not a special message, so append it to
1147 * the end of the connection's list of received messages.
1148 */
1149 crEnqueueMessage(&conn->messageList, msg, len, conn);
1150}
1151
1152
1153/**
1154 * Default handler for receiving data. Called via crNetRecv().
1155 * Typically, the various implementations of the network layer call this.
1156 * \param msg this is the address of the message (of <len> bytes) the
1157 * first part of which is a CRMessage union.
1158 */
1159void
1160crNetDispatchMessage( CRNetReceiveFuncList *rfl, CRConnection *conn,
1161 CRMessage *msg, unsigned int len )
1162{
1163 for ( ; rfl ; rfl = rfl->next)
1164 {
1165 if (rfl->recv( conn, msg, len ))
1166 {
1167 /* Message was consumed by somebody (maybe a SPU).
1168 * All done.
1169 */
1170 return;
1171 }
1172 }
1173 /* Append the message to the connection's message list. It'll be
1174 * consumed later (by crNetPeekMessage or crNetGetMessage and
1175 * then freed with a call to crNetFree()). At this point, the buffer
1176 * *must* have been allocated with crNetAlloc!
1177 */
1178 crNetDefaultRecv( conn, msg, len );
1179}
1180
1181
1182/**
1183 * Return number of messages queued up on the given connection.
1184 */
1185int
1186crNetNumMessages(CRConnection *conn)
1187{
1188 return conn->messageList.numMessages;
1189}
1190
1191
1192/**
1193 * Get the next message in the connection's message list. These are
1194 * message that have already been received. We do not try to read more
1195 * bytes from the network connection.
1196 *
1197 * The crNetFree() function should be called when finished with the message!
1198 *
1199 * \param conn the network connection
1200 * \param message returns a pointer to the next message
1201 * \return length of message (header + payload, in bytes)
1202 */
1203unsigned int
1204crNetPeekMessage( CRConnection *conn, CRMessage **message )
1205{
1206 unsigned int len;
1207 CRConnection *dummyConn = NULL;
1208 if (crDequeueMessageNoBlock(&conn->messageList, message, &len, &dummyConn))
1209 return len;
1210 else
1211 return 0;
1212}
1213
1214
1215/**
1216 * Get the next message from the given network connection. If there isn't
1217 * one already in the linked list of received messages, call crNetRecv()
1218 * until we get something.
1219 *
1220 * \param message returns pointer to the message
1221 * \return total length of message (header + payload, in bytes)
1222 */
1223unsigned int
1224crNetGetMessage( CRConnection *conn, CRMessage **message )
1225{
1226 /* Keep getting work to do */
1227 for (;;)
1228 {
1229 int len = crNetPeekMessage( conn, message );
1230 if (len)
1231 return len;
1232 crNetRecv(
1233#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1234 conn
1235#endif
1236 );
1237 }
1238
1239#if !defined(WINDOWS) && !defined(IRIX) && !defined(IRIX64)
1240 /* silence compiler */
1241 return 0;
1242#endif
1243}
1244
1245
1246/**
1247 * Read a \n-terminated string from a connection. Replace the \n with \0.
1248 * Useful for reading from the mothership.
1249 * \note This is an extremely inefficient way to read a string!
1250 *
1251 * \param conn the network connection
1252 * \param buf buffer in which to place results
1253 */
1254void crNetReadline( CRConnection *conn, void *buf )
1255{
1256 char *temp, c;
1257
1258 if (!conn || conn->type == CR_NO_CONNECTION)
1259 return;
1260
1261 if (conn->type != CR_TCPIP)
1262 {
1263 crError( "Can't do a crNetReadline on anything other than TCPIP (%d).",conn->type );
1264 }
1265 temp = (char*)buf;
1266 for (;;)
1267 {
1268 conn->Recv( conn, &c, 1 );
1269 if (c == '\n')
1270 {
1271 *temp = '\0';
1272 return;
1273 }
1274 *(temp++) = c;
1275 }
1276}
1277
1278#ifdef IN_GUEST
1279uint32_t crNetHostCapsGet()
1280{
1281#ifdef VBOX_WITH_HGCM
1282 if ( cr_net.use_hgcm )
1283 return crVBoxHGCMHostCapsGet();
1284#endif
1285 WARN(("HostCaps supportted for HGCM only!"));
1286 return 0;
1287}
1288#endif
1289
1290/**
1291 * The big boy -- call this function to see (non-blocking) if there is
1292 * any pending work. If there is, the networking layer's "work received"
1293 * handler will be called, so this function only returns a flag. Work
1294 * is assumed to be placed on queues for processing by the handler.
1295 */
1296int crNetRecv(
1297#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1298 CRConnection *conn
1299#endif
1300 )
1301{
1302 int found_work = 0;
1303
1304 if ( cr_net.use_tcpip )
1305 found_work += crTCPIPRecv();
1306#ifdef VBOX_WITH_HGCM
1307 if ( cr_net.use_hgcm )
1308 found_work += crVBoxHGCMRecv(
1309#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1310 conn
1311#endif
1312 );
1313#endif
1314#ifdef SDP_SUPPORT
1315 if ( cr_net.use_sdp )
1316 found_work += crSDPRecv();
1317#endif
1318#ifdef IB_SUPPORT
1319 if ( cr_net.use_ib )
1320 found_work += crIBRecv();
1321#endif
1322 if ( cr_net.use_udp )
1323 found_work += crUDPTCPIPRecv();
1324
1325 if ( cr_net.use_file )
1326 found_work += crFileRecv();
1327
1328#ifdef GM_SUPPORT
1329 if ( cr_net.use_gm )
1330 found_work += crGmRecv();
1331#endif
1332
1333#ifdef TEAC_SUPPORT
1334 if ( cr_net.use_teac )
1335 found_work += crTeacRecv();
1336#endif
1337
1338#ifdef TCSCOMM_SUPPORT
1339 if ( cr_net.use_tcscomm )
1340 found_work += crTcscommRecv();
1341#endif
1342
1343 return found_work;
1344}
1345
1346
1347/**
1348 * Teac/TSComm only
1349 */
1350void
1351crNetSetRank( int my_rank )
1352{
1353 cr_net.my_rank = my_rank;
1354#ifdef TEAC_SUPPORT
1355 crTeacSetRank( cr_net.my_rank );
1356#endif
1357#ifdef TCSCOMM_SUPPORT
1358 crTcscommSetRank( cr_net.my_rank );
1359#endif
1360}
1361
1362/**
1363 * Teac/TSComm only
1364 */
1365void
1366crNetSetContextRange( int low_context, int high_context )
1367{
1368#ifdef TEAC_SUPPORT
1369 crTeacSetContextRange( low_context, high_context );
1370#endif
1371#ifdef TCSCOMM_SUPPORT
1372 crTcscommSetContextRange( low_context, high_context );
1373#endif
1374}
1375
1376/**
1377 * Teac/TSComm only
1378 */
1379void
1380crNetSetNodeRange( const char *low_node, const char *high_node )
1381{
1382#ifdef TEAC_SUPPORT
1383 crTeacSetNodeRange( low_node, high_node );
1384#endif
1385#ifdef TCSCOMM_SUPPORT
1386 crTcscommSetNodeRange( low_node, high_node );
1387#endif
1388}
1389
1390/**
1391 * Teac/TSComm only
1392 */
1393void
1394crNetSetKey( const unsigned char* key, const int keyLength )
1395{
1396#ifdef TEAC_SUPPORT
1397 crTeacSetKey( key, keyLength );
1398#endif
1399}
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