VirtualBox

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

Last change on this file since 40124 was 40124, checked in by vboxsync, 13 years ago

crOpenGL: add some extensions required for wined3d+wddm

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