VirtualBox

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

Last change on this file since 33116 was 33116, checked in by vboxsync, 14 years ago

wddm/3d: chromium hgsmi transport (guest part, disabled)

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