VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/tcpip.c@ 58529

最後變更 在這個檔案從58529是 53726,由 vboxsync 提交於 10 年 前

properties.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 38.7 KB
 
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#ifdef WINDOWS
8#define WIN32_LEAN_AND_MEAN
9#pragma warning( push, 3 )
10#include <winsock2.h>
11#pragma warning( pop )
12#pragma warning( disable : 4514 )
13#pragma warning( disable : 4127 )
14# ifndef VBOX
15typedef int ssize_t;
16# endif
17#else
18#include <sys/types.h>
19#include <sys/wait.h>
20#ifdef OSF1
21typedef int socklen_t;
22#endif
23#include <sys/socket.h>
24#include <sys/time.h>
25#include <netinet/in.h>
26#include <netinet/tcp.h>
27#include <arpa/inet.h>
28#include <netdb.h>
29#include <unistd.h>
30#endif
31
32#include <limits.h>
33#include <stdlib.h>
34#include <stdio.h>
35#include <errno.h>
36#include <signal.h>
37#include <string.h>
38#ifdef AIX
39#include <strings.h>
40#endif
41
42#ifdef LINUX
43#include <sys/ioctl.h>
44#include <unistd.h>
45#endif
46
47#include "cr_error.h"
48#include "cr_mem.h"
49#include "cr_string.h"
50#include "cr_bufpool.h"
51#include "cr_net.h"
52#include "cr_endian.h"
53#include "cr_threads.h"
54#include "cr_environment.h"
55#include "net_internals.h"
56
57#ifdef ADDRINFO
58#define PF PF_UNSPEC
59#endif
60
61#ifdef WINDOWS
62#define EADDRINUSE WSAEADDRINUSE
63#define ECONNREFUSED WSAECONNREFUSED
64#endif
65
66#ifdef WINDOWS
67
68#undef ECONNRESET
69#define ECONNRESET WSAECONNRESET
70#undef EINTR
71#define EINTR WSAEINTR
72
73int crTCPIPErrno( void )
74{
75 return WSAGetLastError( );
76}
77
78char *crTCPIPErrorString( int err )
79{
80 static char buf[512], *temp;
81
82 sprintf( buf, "err=%d", err );
83
84#define X(x) crStrcpy(buf,x); break
85
86 switch ( err )
87 {
88 case WSAECONNREFUSED: X( "connection refused" );
89 case WSAECONNRESET: X( "connection reset" );
90 default:
91 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
92 FORMAT_MESSAGE_FROM_SYSTEM |
93 FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, err,
94 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
95 (LPTSTR) &temp, 0, NULL );
96 if ( temp )
97 {
98 crStrncpy( buf, temp, sizeof(buf)-1 );
99 buf[sizeof(buf)-1] = 0;
100 }
101 }
102
103#undef X
104
105 temp = buf + crStrlen(buf) - 1;
106 while ( temp > buf && isspace( *temp ) )
107 {
108 *temp = '\0';
109 temp--;
110 }
111
112 return buf;
113}
114
115#else /* WINDOWS */
116
117int crTCPIPErrno( void )
118{
119 int err = errno;
120 errno = 0;
121 return err;
122}
123
124char *crTCPIPErrorString( int err )
125{
126 static char buf[512], *temp;
127
128 temp = strerror( err );
129 if ( temp )
130 {
131 crStrncpy( buf, temp, sizeof(buf)-1 );
132 buf[sizeof(buf)-1] = 0;
133 }
134 else
135 {
136 sprintf( buf, "err=%d", err );
137 }
138
139 return buf;
140}
141
142#endif /* WINDOWS */
143
144
145/*
146 * Socket callbacks. When a socket is created or destroyed we will
147 * call these callback functions.
148 * XXX Currently only implemented for TCP/IP.
149 * XXX Maybe have lists of callbacks?
150 */
151static CRSocketCallbackProc SocketCreateCallback = NULL;
152static CRSocketCallbackProc SocketDestroyCallback = NULL;
153
154void
155crRegisterSocketCallback(int mode, CRSocketCallbackProc proc)
156{
157 if (mode == CR_SOCKET_CREATE) {
158 SocketCreateCallback = proc;
159 }
160 else if (mode == CR_SOCKET_DESTROY) {
161 SocketDestroyCallback = proc;
162 }
163 else {
164 crError("Invalid crRegisterSocketCallbac mode=%d", mode);
165 }
166}
167
168
169
170void crCloseSocket( CRSocket sock )
171{
172 int fail;
173
174 if (sock <= 0)
175 return;
176
177 if (SocketDestroyCallback) {
178 SocketDestroyCallback(CR_SOCKET_DESTROY, sock);
179 }
180
181#ifdef WINDOWS
182 fail = ( closesocket( sock ) != 0 );
183#else
184 shutdown( sock, 2 /* RDWR */ );
185 fail = ( close( sock ) != 0 );
186#endif
187 if ( fail )
188 {
189 int err = crTCPIPErrno( );
190 crWarning( "crCloseSocket( sock=%d ): %s",
191 sock, crTCPIPErrorString( err ) );
192 }
193}
194
195cr_tcpip_data cr_tcpip;
196
197/**
198 * Read len bytes from socket, and store in buffer.
199 * \return 1 if success, -1 if error, 0 if sender exited.
200 */
201int
202__tcpip_read_exact( CRSocket sock, void *buf, unsigned int len )
203{
204 char *dst = (char *) buf;
205 /*
206 * Shouldn't write to a non-existent socket, ie when
207 * crTCPIPDoDisconnect has removed it from the pool
208 */
209 if ( sock <= 0 )
210 return 1;
211
212 while ( len > 0 )
213 {
214 const int num_read = recv( sock, dst, (int) len, 0 );
215
216#ifdef WINDOWS_XXXX
217 /* MWE: why is this necessary for windows??? Does it return a
218 "good" value for num_bytes despite having a reset
219 connection? */
220 if ( crTCPIPErrno( ) == ECONNRESET )
221 return -1;
222#endif
223
224 if ( num_read < 0 )
225 {
226 int error = crTCPIPErrno();
227 switch( error )
228 {
229 case EINTR:
230 crWarning( "__tcpip_read_exact(TCPIP): "
231 "caught an EINTR, looping for more data" );
232 continue;
233 case EFAULT:
234 crWarning( "EFAULT" );
235 break;
236 case EINVAL:
237 crWarning( "EINVAL" );
238 break;
239 default:
240 break;
241 }
242 crWarning( "Bad bad bad socket error: %s", crTCPIPErrorString( error ) );
243 return -1;
244 }
245
246 if ( num_read == 0 )
247 {
248 /* client exited gracefully */
249 return 0;
250 }
251
252 dst += num_read;
253 len -= num_read;
254 }
255
256 return 1;
257}
258
259void
260crTCPIPReadExact( CRConnection *conn, void *buf, unsigned int len )
261{
262 if ( __tcpip_read_exact( conn->tcp_socket, buf, len ) <= 0 )
263 {
264 __tcpip_dead_connection( conn );
265 }
266}
267
268/**
269 * Write the given buffer of len bytes on the socket.
270 * \return 1 if OK, negative value if error.
271 */
272int
273__tcpip_write_exact( CRSocket sock, const void *buf, unsigned int len )
274{
275 const char *src = (const char *) buf;
276
277 /*
278 * Shouldn't write to a non-existent socket, ie when
279 * crTCPIPDoDisconnect has removed it from the pool
280 */
281 if ( sock <= 0 )
282 return 1;
283
284 while ( len > 0 )
285 {
286 const int num_written = send( sock, src, len, 0 );
287 if ( num_written <= 0 )
288 {
289 int err;
290 if ( (err = crTCPIPErrno( )) == EINTR )
291 {
292 crWarning("__tcpip_write_exact(TCPIP): caught an EINTR, continuing");
293 continue;
294 }
295
296 return -err;
297 }
298
299 len -= num_written;
300 src += num_written;
301 }
302
303 return 1;
304}
305
306void
307crTCPIPWriteExact( CRConnection *conn, const void *buf, unsigned int len )
308{
309 if ( __tcpip_write_exact( conn->tcp_socket, buf, len) <= 0 )
310 {
311 __tcpip_dead_connection( conn );
312 }
313}
314
315
316/**
317 * Make sockets do what we want:
318 *
319 * 1) Change the size of the send/receive buffers to 64K
320 * 2) Turn off Nagle's algorithm
321 */
322static void
323spankSocket( CRSocket sock )
324{
325 /* why do we do 1) ? things work much better for me to push the
326 * the buffer size way up -- karl
327 */
328#ifdef LINUX
329 int sndbuf = 1*1024*1024;
330#else
331 int sndbuf = 64*1024;
332#endif
333
334 int rcvbuf = sndbuf;
335 int so_reuseaddr = 1;
336 int tcp_nodelay = 1;
337
338 if ( setsockopt( sock, SOL_SOCKET, SO_SNDBUF,
339 (char *) &sndbuf, sizeof(sndbuf) ) )
340 {
341 int err = crTCPIPErrno( );
342 crWarning( "setsockopt( SO_SNDBUF=%d ) : %s",
343 sndbuf, crTCPIPErrorString( err ) );
344 }
345
346 if ( setsockopt( sock, SOL_SOCKET, SO_RCVBUF,
347 (char *) &rcvbuf, sizeof(rcvbuf) ) )
348 {
349 int err = crTCPIPErrno( );
350 crWarning( "setsockopt( SO_RCVBUF=%d ) : %s",
351 rcvbuf, crTCPIPErrorString( err ) );
352 }
353
354
355 if ( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR,
356 (char *) &so_reuseaddr, sizeof(so_reuseaddr) ) )
357 {
358 int err = crTCPIPErrno( );
359 crWarning( "setsockopt( SO_REUSEADDR=%d ) : %s",
360 so_reuseaddr, crTCPIPErrorString( err ) );
361 }
362
363 if ( setsockopt( sock, IPPROTO_TCP, TCP_NODELAY,
364 (char *) &tcp_nodelay, sizeof(tcp_nodelay) ) )
365 {
366 int err = crTCPIPErrno( );
367 crWarning( "setsockopt( TCP_NODELAY=%d )"
368 " : %s", tcp_nodelay, crTCPIPErrorString( err ) );
369 }
370}
371
372
373#if defined( WINDOWS ) || defined( IRIX ) || defined( IRIX64 )
374typedef int socklen_t;
375#endif
376
377
378/**
379 * Create a listening socket using the given port.
380 * Caller can then pass the socket to accept().
381 * If the port is one that's been seen before, we'll reuse/return the
382 * previously create socket.
383 */
384static int
385CreateListeningSocket(int port)
386{
387 /* XXX should use an unbounded list here instead of parallel arrays... */
388#define MAX_PORTS 100
389 static int ports[MAX_PORTS];
390 static int sockets[MAX_PORTS];
391 static int count = 0;
392 int i, sock = -1;
393
394 /* search to see if we've seen this port before */
395 for (i = 0; i < count; i++) {
396 if (ports[i] == port) {
397 return sockets[i];
398 }
399 }
400
401 /* new port so create new socket */
402 {
403 int err;
404#ifndef ADDRINFO
405 struct sockaddr_in servaddr;
406#endif
407
408 /* with the new OOB stuff, we can have multiple ports being
409 * accepted on, so we need to redo the server socket every time.
410 */
411#ifndef ADDRINFO
412 sock = socket( AF_INET, SOCK_STREAM, 0 );
413 if ( sock == -1 )
414 {
415 err = crTCPIPErrno( );
416 crError( "Couldn't create socket: %s", crTCPIPErrorString( err ) );
417 }
418 spankSocket( sock );
419
420 servaddr.sin_family = AF_INET;
421 servaddr.sin_addr.s_addr = INADDR_ANY;
422 servaddr.sin_port = htons( (short) port );
423
424 if ( bind( sock, (struct sockaddr *) &servaddr, sizeof(servaddr) ) )
425 {
426 err = crTCPIPErrno( );
427 crError( "Couldn't bind to socket (port=%d): %s",
428 port, crTCPIPErrorString( err ) );
429 }
430
431 if ( listen( sock, 100 /* max pending connections */ ) )
432 {
433 err = crTCPIPErrno( );
434 crError( "Couldn't listen on socket: %s", crTCPIPErrorString( err ) );
435 }
436#else
437 char port_s[NI_MAXSERV];
438 struct addrinfo *res,*cur;
439 struct addrinfo hints;
440
441 sprintf(port_s, "%u", (short unsigned) port);
442
443 crMemset(&hints, 0, sizeof(hints));
444 hints.ai_flags = AI_PASSIVE;
445 hints.ai_family = PF;
446 hints.ai_socktype = SOCK_STREAM;
447
448 err = getaddrinfo( NULL, port_s, &hints, &res );
449 if ( err )
450 crError( "Couldn't find local TCP port %s: %s",
451 port_s, gai_strerror(err) );
452
453 for (cur=res;cur;cur=cur->ai_next)
454 {
455 sock = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
456 if ( sock == -1 )
457 {
458 err = crTCPIPErrno( );
459 if (err != EAFNOSUPPORT)
460 crWarning("Couldn't create socket of family %i: %s, trying another",
461 cur->ai_family, crTCPIPErrorString( err ) );
462 continue;
463 }
464 spankSocket( sock );
465
466 if ( bind( sock, cur->ai_addr, cur->ai_addrlen ) )
467 {
468 err = crTCPIPErrno( );
469 crWarning( "Couldn't bind to socket (port=%d): %s",
470 port, crTCPIPErrorString( err ) );
471 crCloseSocket( sock );
472 continue;
473 }
474
475 if ( listen( sock, 100 /* max pending connections */ ) )
476 {
477 err = crTCPIPErrno( );
478 crWarning("Couldn't listen on socket: %s", crTCPIPErrorString(err));
479 crCloseSocket( sock );
480 continue;
481 }
482 break;
483 }
484 freeaddrinfo(res);
485 if (!cur)
486 crError( "Couldn't find/bind local TCP port %s", port_s);
487#endif
488 }
489
490 /* save the new port/socket */
491 if (count == MAX_PORTS) {
492 crError("Fatal error in tcpip layer: too many listening ports/sockets");
493 }
494 ports[count] = port;
495 sockets[count] = sock;
496 count++;
497
498 return sock;
499}
500
501
502
503
504void
505crTCPIPAccept( CRConnection *conn, const char *hostname, unsigned short port )
506{
507 int err;
508 socklen_t addr_length;
509#ifndef ADDRINFO
510 struct hostent *host;
511 struct in_addr sin_addr;
512 struct sockaddr addr;
513#else
514 struct sockaddr_storage addr;
515 char host[NI_MAXHOST];
516#endif
517
518 cr_tcpip.server_sock = CreateListeningSocket(port);
519
520 /* If brokered, we'll contact the mothership to broker the network
521 * connection. We'll send the mothership our hostname, the port and
522 * our endianness and will get in return a connection ID number.
523 */
524 if (conn->broker) {
525 crError("There shouldn't be any brokered connections in VirtualBox");
526 }
527
528 addr_length = sizeof( addr );
529 conn->tcp_socket = accept( cr_tcpip.server_sock, (struct sockaddr *) &addr, &addr_length );
530 if (conn->tcp_socket == -1)
531 {
532 err = crTCPIPErrno( );
533 crError( "Couldn't accept client: %s", crTCPIPErrorString( err ) );
534 }
535
536 if (SocketCreateCallback) {
537 SocketCreateCallback(CR_SOCKET_CREATE, conn->tcp_socket);
538 }
539
540#ifndef ADDRINFO
541 sin_addr = ((struct sockaddr_in *) &addr)->sin_addr;
542 host = gethostbyaddr( (char *) &sin_addr, sizeof( sin_addr), AF_INET );
543 if (host == NULL )
544 {
545 char *temp = inet_ntoa( sin_addr );
546 conn->hostname = crStrdup( temp );
547 }
548#else
549 err = getnameinfo ( (struct sockaddr *) &addr, addr_length,
550 host, sizeof( host),
551 NULL, 0, NI_NAMEREQD);
552 if ( err )
553 {
554 err = getnameinfo ( (struct sockaddr *) &addr, addr_length,
555 host, sizeof( host),
556 NULL, 0, NI_NUMERICHOST);
557 if ( err ) /* shouldn't ever happen */
558 conn->hostname = crStrdup("unknown ?!");
559 else
560 conn->hostname = crStrdup( host );
561 }
562#endif
563 else
564 {
565 char *temp;
566#ifndef ADDRINFO
567 conn->hostname = crStrdup( host->h_name );
568#else
569 conn->hostname = crStrdup( host );
570#endif
571
572 temp = conn->hostname;
573 while (*temp && *temp != '.' )
574 temp++;
575 *temp = '\0';
576 }
577
578#ifdef RECV_BAIL_OUT
579 err = sizeof(unsigned int);
580 if ( getsockopt( conn->tcp_socket, SOL_SOCKET, SO_RCVBUF,
581 (char *) &conn->krecv_buf_size, &err ) )
582 {
583 conn->krecv_buf_size = 0;
584 }
585#endif
586
587 crDebug( "Accepted connection from \"%s\".", conn->hostname );
588}
589
590
591void *
592crTCPIPAlloc( CRConnection *conn )
593{
594 CRTCPIPBuffer *buf;
595
596#ifdef CHROMIUM_THREADSAFE
597 crLockMutex(&cr_tcpip.mutex);
598#endif
599
600 buf = (CRTCPIPBuffer *) crBufferPoolPop( cr_tcpip.bufpool, conn->buffer_size );
601
602 if ( buf == NULL )
603 {
604 crDebug("Buffer pool %p was empty; allocated new %d byte buffer.",
605 cr_tcpip.bufpool,
606 (unsigned int)sizeof(CRTCPIPBuffer) + conn->buffer_size);
607 buf = (CRTCPIPBuffer *)
608 crAlloc( sizeof(CRTCPIPBuffer) + conn->buffer_size );
609 buf->magic = CR_TCPIP_BUFFER_MAGIC;
610 buf->kind = CRTCPIPMemory;
611 buf->pad = 0;
612 buf->allocated = conn->buffer_size;
613 }
614
615#ifdef CHROMIUM_THREADSAFE
616 crUnlockMutex(&cr_tcpip.mutex);
617#endif
618
619 return (void *)( buf + 1 );
620}
621
622
623static void
624crTCPIPSingleRecv( CRConnection *conn, void *buf, unsigned int len )
625{
626 crTCPIPReadExact( conn, buf, len );
627}
628
629
630static void
631crTCPIPSend( CRConnection *conn, void **bufp,
632 const void *start, unsigned int len )
633{
634 if ( !conn || conn->type == CR_NO_CONNECTION )
635 return;
636
637 if (!bufp) {
638 /* We're sending a user-allocated buffer.
639 * Simply write the length & the payload and return.
640 */
641 const int sendable_len = conn->swap ? SWAP32(len) : len;
642 crTCPIPWriteExact( conn, &sendable_len, sizeof(len) );
643 if (!conn || conn->type == CR_NO_CONNECTION)
644 return;
645 crTCPIPWriteExact( conn, start, len );
646 }
647 else {
648 /* The region [start .. start + len + 1] lies within a buffer that
649 * was allocated with crTCPIPAlloc() and can be put into the free
650 * buffer pool when we're done sending it.
651 */
652 CRTCPIPBuffer *tcpip_buffer;
653 unsigned int *lenp;
654
655 tcpip_buffer = (CRTCPIPBuffer *)(*bufp) - 1;
656
657 CRASSERT( tcpip_buffer->magic == CR_TCPIP_BUFFER_MAGIC );
658
659 /* All of the buffers passed to the send function were allocated
660 * with crTCPIPAlloc(), which includes a header with a 4 byte
661 * pad field, to insure that we always have a place to write
662 * the length field, even when start == *bufp.
663 */
664 lenp = (unsigned int *) start - 1;
665 *lenp = conn->swap ? SWAP32(len) : len;
666
667 crTCPIPWriteExact(conn, lenp, len + sizeof(unsigned int));
668
669 /* Reclaim this pointer for reuse */
670#ifdef CHROMIUM_THREADSAFE
671 crLockMutex(&cr_tcpip.mutex);
672#endif
673 crBufferPoolPush(cr_tcpip.bufpool, tcpip_buffer, tcpip_buffer->allocated);
674#ifdef CHROMIUM_THREADSAFE
675 crUnlockMutex(&cr_tcpip.mutex);
676#endif
677 /* Since the buffer's now in the 'free' buffer pool, the caller can't
678 * use it any more. Setting bufp to NULL will make sure the caller
679 * doesn't try to re-use the buffer.
680 */
681 *bufp = NULL;
682 }
683}
684
685
686void
687__tcpip_dead_connection( CRConnection *conn )
688{
689 crDebug( "Dead connection (sock=%d, host=%s), removing from pool",
690 conn->tcp_socket, conn->hostname );
691 /* remove from connection pool */
692 crTCPIPDoDisconnect( conn );
693}
694
695
696int
697__crSelect( int n, fd_set *readfds, int sec, int usec )
698{
699 for ( ; ; )
700 {
701 int err, num_ready;
702
703 if (sec || usec)
704 {
705 /* We re-init everytime for Linux, as it corrupts
706 * the timeout structure, but other OS's
707 * don't have a problem with it.
708 */
709 struct timeval timeout;
710 timeout.tv_sec = sec;
711 timeout.tv_usec = usec;
712 num_ready = select( n, readfds, NULL, NULL, &timeout );
713 }
714 else
715 num_ready = select( n, readfds, NULL, NULL, NULL );
716
717 if ( num_ready >= 0 )
718 {
719 return num_ready;
720 }
721
722 err = crTCPIPErrno( );
723 if ( err == EINTR )
724 {
725 crWarning( "select interrupted by an unblocked signal, trying again" );
726 }
727 else
728 {
729 crError( "select failed: %s", crTCPIPErrorString( err ) );
730 }
731 }
732}
733
734
735void
736crTCPIPFree( CRConnection *conn, void *buf )
737{
738 CRTCPIPBuffer *tcpip_buffer = (CRTCPIPBuffer *) buf - 1;
739
740 CRASSERT( tcpip_buffer->magic == CR_TCPIP_BUFFER_MAGIC );
741 conn->recv_credits += tcpip_buffer->len;
742
743 switch ( tcpip_buffer->kind )
744 {
745 case CRTCPIPMemory:
746#ifdef CHROMIUM_THREADSAFE
747 crLockMutex(&cr_tcpip.mutex);
748#endif
749 if (cr_tcpip.bufpool) {
750 /* pool may have been deallocated just a bit earlier in response
751 * to a SIGPIPE (Broken Pipe) signal.
752 */
753 crBufferPoolPush( cr_tcpip.bufpool, tcpip_buffer, tcpip_buffer->allocated );
754 }
755#ifdef CHROMIUM_THREADSAFE
756 crUnlockMutex(&cr_tcpip.mutex);
757#endif
758 break;
759
760 case CRTCPIPMemoryBig:
761 crFree( tcpip_buffer );
762 break;
763
764 default:
765 crError( "Weird buffer kind trying to free in crTCPIPFree: %d", tcpip_buffer->kind );
766 }
767}
768
769
770/**
771 * Check if message type is GATHER. If so, process it specially.
772 * \return number of bytes which were consumed
773 */
774static int
775crTCPIPUserbufRecv(CRConnection *conn, CRMessage *msg)
776{
777 if (msg->header.type == CR_MESSAGE_GATHER) {
778 /* grab the offset and the length */
779 const int len = 2 * sizeof(unsigned int); /* was unsigned long!!!! */
780 unsigned int buf[2];
781
782 if (__tcpip_read_exact(conn->tcp_socket, buf, len) <= 0)
783 {
784 __tcpip_dead_connection( conn );
785 }
786 msg->gather.offset = buf[0];
787 msg->gather.len = buf[1];
788
789 /* read the rest into the userbuf */
790 if (buf[0] + buf[1] > (unsigned int) conn->userbuf_len)
791 {
792 crDebug("userbuf for Gather Message is too small!");
793 return len;
794 }
795
796 if (__tcpip_read_exact(conn->tcp_socket,
797 conn->userbuf + buf[0], buf[1]) <= 0)
798 {
799 __tcpip_dead_connection( conn );
800 }
801 return len + buf[1];
802 }
803 else {
804 return 0;
805 }
806}
807
808
809/**
810 * Receive the next message on the given connection.
811 * If we're being called by crTCPIPRecv(), we already know there's
812 * something to receive.
813 */
814static void
815crTCPIPReceiveMessage(CRConnection *conn)
816{
817 CRMessage *msg;
818 CRMessageType cached_type;
819 CRTCPIPBuffer *tcpip_buffer;
820 unsigned int len, total, leftover;
821 const int sock = conn->tcp_socket;
822
823 /* Our gigE board is acting odd. If we recv() an amount
824 * less than what is already in the RECVBUF, performance
825 * goes into the toilet (somewhere around a factor of 3).
826 * This is an ugly hack, but seems to get around whatever
827 * funk is being produced
828 *
829 * Remember to set your kernel recv buffers to be bigger
830 * than the framebuffer 'chunk' you are sending (see
831 * sysctl -a | grep rmem) , or this will really have no
832 * effect. --karl
833 */
834#ifdef RECV_BAIL_OUT
835 {
836 int inbuf;
837 (void) recv(sock, &len, sizeof(len), MSG_PEEK);
838 ioctl(conn->tcp_socket, FIONREAD, &inbuf);
839
840 if ((conn->krecv_buf_size > len) && (inbuf < len))
841 return;
842 }
843#endif
844
845 /* this reads the length of the message */
846 if ( __tcpip_read_exact( sock, &len, sizeof(len)) <= 0 )
847 {
848 __tcpip_dead_connection( conn );
849 return;
850 }
851
852 if (conn->swap)
853 len = SWAP32(len);
854
855 CRASSERT( len > 0 );
856
857 if ( len <= conn->buffer_size )
858 {
859 /* put in pre-allocated buffer */
860 tcpip_buffer = (CRTCPIPBuffer *) crTCPIPAlloc( conn ) - 1;
861 }
862 else
863 {
864 /* allocate new buffer */
865 tcpip_buffer = (CRTCPIPBuffer *) crAlloc( sizeof(*tcpip_buffer) + len );
866 tcpip_buffer->magic = CR_TCPIP_BUFFER_MAGIC;
867 tcpip_buffer->kind = CRTCPIPMemoryBig;
868 tcpip_buffer->pad = 0;
869 }
870
871 tcpip_buffer->len = len;
872
873 /* if we have set a userbuf, and there is room in it, we probably
874 * want to stick the message into that, instead of our allocated
875 * buffer.
876 */
877 leftover = 0;
878 total = len;
879 if ((conn->userbuf != NULL)
880 && (conn->userbuf_len >= (int) sizeof(CRMessageHeader)))
881 {
882 leftover = len - sizeof(CRMessageHeader);
883 total = sizeof(CRMessageHeader);
884 }
885
886 if ( __tcpip_read_exact( sock, tcpip_buffer + 1, total) <= 0 )
887 {
888 crWarning( "Bad juju: %d %d on socket 0x%x", tcpip_buffer->allocated,
889 total, sock );
890 crFree( tcpip_buffer );
891 __tcpip_dead_connection( conn );
892 return;
893 }
894
895 conn->recv_credits -= total;
896 conn->total_bytes_recv += total;
897
898 msg = (CRMessage *) (tcpip_buffer + 1);
899 cached_type = msg->header.type;
900 if (conn->swap)
901 {
902 msg->header.type = (CRMessageType) SWAP32( msg->header.type );
903 msg->header.conn_id = (CRMessageType) SWAP32( msg->header.conn_id );
904 }
905
906 /* if there is still data pending, it should go into the user buffer */
907 if (leftover)
908 {
909 const unsigned int handled = crTCPIPUserbufRecv(conn, msg);
910
911 /* if there is anything left, plop it into the recv_buffer */
912 if (leftover - handled)
913 {
914 if ( __tcpip_read_exact( sock, tcpip_buffer + 1 + total, leftover-handled) <= 0 )
915 {
916 crWarning( "Bad juju: %d %d", tcpip_buffer->allocated, leftover-handled);
917 crFree( tcpip_buffer );
918 __tcpip_dead_connection( conn );
919 return;
920 }
921 }
922
923 conn->recv_credits -= handled;
924 conn->total_bytes_recv += handled;
925 }
926
927 crNetDispatchMessage( cr_tcpip.recv_list, conn, msg, len );
928#if 0
929 crLogRead( len );
930#endif
931
932 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
933 * OOB messages are the programmer's problem. -- Humper 12/17/01
934 */
935 if (cached_type != CR_MESSAGE_OPCODES
936 && cached_type != CR_MESSAGE_OOB
937 && cached_type != CR_MESSAGE_GATHER)
938 {
939 crTCPIPFree( conn, tcpip_buffer + 1 );
940 }
941}
942
943
944/**
945 * Loop over all TCP/IP connections, reading incoming data on those
946 * that are ready.
947 */
948int
949crTCPIPRecv( void )
950{
951 /* ensure we don't get caught with a new thread connecting */
952 const int num_conns = cr_tcpip.num_conns;
953 int num_ready, max_fd, i;
954 fd_set read_fds;
955 int msock = -1; /* assumed mothership socket */
956#if CRAPPFAKER_SHOULD_DIE
957 int none_left = 1;
958#endif
959
960#ifdef CHROMIUM_THREADSAFE
961 crLockMutex(&cr_tcpip.recvmutex);
962#endif
963
964 /*
965 * Loop over all connections and determine which are TCP/IP connections
966 * that are ready to be read.
967 */
968 max_fd = 0;
969 FD_ZERO( &read_fds );
970 for ( i = 0; i < num_conns; i++ )
971 {
972 CRConnection *conn = cr_tcpip.conns[i];
973 if ( !conn || conn->type == CR_NO_CONNECTION )
974 continue;
975
976#if CRAPPFAKER_SHOULD_DIE
977 none_left = 0;
978#endif
979
980 if ( conn->recv_credits > 0 || conn->type != CR_TCPIP )
981 {
982 /*
983 * NOTE: may want to always put the FD in the descriptor
984 * set so we'll notice broken connections. Down in the
985 * loop that iterates over the ready sockets only peek
986 * (MSG_PEEK flag to recv()?) if the connection isn't
987 * enabled.
988 */
989#if 0 /* not used - see below */
990#ifndef ADDRINFO
991 struct sockaddr s;
992#else
993 struct sockaddr_storage s;
994#endif
995 socklen_t slen;
996#endif
997 fd_set only_fd; /* testing single fd */
998 CRSocket sock = conn->tcp_socket;
999
1000 if ( (int) sock + 1 > max_fd )
1001 max_fd = (int) sock + 1;
1002 FD_SET( sock, &read_fds );
1003
1004 /* KLUDGE CITY......
1005 *
1006 * With threads there's a race condition between
1007 * TCPIPRecv and TCPIPSingleRecv when new
1008 * clients are connecting, thus new mothership
1009 * connections are also being established.
1010 * This code below is to check that we're not
1011 * in a state of accepting the socket without
1012 * connecting to it otherwise we fail with
1013 * ENOTCONN later. But, this is really a side
1014 * effect of this routine catching a motherships
1015 * socket connection and reading data that wasn't
1016 * really meant for us. It was really meant for
1017 * TCPIPSingleRecv. So, if we detect an
1018 * in-progress connection we set the msock id
1019 * so that we can assume the motherships socket
1020 * and skip over them.
1021 */
1022
1023 FD_ZERO(&only_fd);
1024 FD_SET( sock, &only_fd );
1025
1026#if 0 /* Disabled on Dec 13 2005 by BrianP - seems to cause trouble */
1027 slen = sizeof( s );
1028 /* Check that the socket is REALLY connected */
1029 /* Doesn't this call introduce some inefficiency??? (BP) */
1030 if (getpeername(sock, (struct sockaddr *) &s, &slen) < 0) {
1031 /* Another kludge.....
1032 * If we disconnect a socket without writing
1033 * anything to it, we end up here. Detect
1034 * the disconnected socket by checking if
1035 * we've ever sent something and then
1036 * disconnect it.
1037 *
1038 * I think the networking layer needs
1039 * a bit of a re-write.... Alan.
1040 */
1041 if (conn->total_bytes_sent > 0) {
1042 crTCPIPDoDisconnect( conn );
1043 }
1044 FD_CLR(sock, &read_fds);
1045 msock = sock;
1046 }
1047#endif
1048 /*
1049 * Nope, that last socket we've just caught in
1050 * the connecting phase. We've probably found
1051 * a mothership connection here, and we shouldn't
1052 * process it
1053 */
1054 if ((int)sock == msock+1)
1055 FD_CLR(sock, &read_fds);
1056 }
1057 }
1058
1059#if CRAPPFAKER_SHOULD_DIE
1060 if (none_left) {
1061 /*
1062 * Caught no more connections.
1063 * Review this if we want to try
1064 * restarting crserver's dynamically.
1065 */
1066#ifdef CHROMIUM_THREADSAFE
1067 crUnlockMutex(&cr_tcpip.recvmutex);
1068#endif
1069 crError("No more connections to process, terminating...\n");
1070 exit(0); /* shouldn't get here */
1071 }
1072#endif
1073
1074 if (!max_fd) {
1075#ifdef CHROMIUM_THREADSAFE
1076 crUnlockMutex(&cr_tcpip.recvmutex);
1077#endif
1078 return 0;
1079 }
1080
1081 if ( num_conns ) {
1082 num_ready = __crSelect( max_fd, &read_fds, 0, 500 );
1083 }
1084 else {
1085 crWarning( "Waiting for first connection..." );
1086 num_ready = __crSelect( max_fd, &read_fds, 0, 0 );
1087 }
1088
1089 if ( num_ready == 0 ) {
1090#ifdef CHROMIUM_THREADSAFE
1091 crUnlockMutex(&cr_tcpip.recvmutex);
1092#endif
1093 return 0;
1094 }
1095
1096 /*
1097 * Loop over connections, receive data on the TCP/IP connections that
1098 * we determined are ready above.
1099 */
1100 for ( i = 0; i < num_conns; i++ )
1101 {
1102 CRConnection *conn = cr_tcpip.conns[i];
1103 CRSocket sock;
1104
1105 if ( !conn || conn->type == CR_NO_CONNECTION )
1106 continue;
1107
1108 /* Added by Samuel Thibault during TCP/IP / UDP code factorization */
1109 if ( conn->type != CR_TCPIP )
1110 continue;
1111
1112 sock = conn->tcp_socket;
1113 if ( !FD_ISSET( sock, &read_fds ) )
1114 continue;
1115
1116 if (conn->threaded)
1117 continue;
1118
1119 crTCPIPReceiveMessage(conn);
1120 }
1121
1122#ifdef CHROMIUM_THREADSAFE
1123 crUnlockMutex(&cr_tcpip.recvmutex);
1124#endif
1125
1126 return 1;
1127}
1128
1129
1130static void
1131crTCPIPHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1132{
1133 CRTCPIPBuffer *buf = ((CRTCPIPBuffer *) msg) - 1;
1134
1135 /* build a header so we can delete the message later */
1136 buf->magic = CR_TCPIP_BUFFER_MAGIC;
1137 buf->kind = CRTCPIPMemory;
1138 buf->len = len;
1139 buf->pad = 0;
1140
1141 crNetDispatchMessage( cr_tcpip.recv_list, conn, msg, len );
1142}
1143
1144
1145static void
1146crTCPIPInstantReclaim( CRConnection *conn, CRMessage *mess )
1147{
1148 crTCPIPFree( conn, mess );
1149}
1150
1151
1152void
1153crTCPIPInit( CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl,
1154 unsigned int mtu )
1155{
1156 (void) mtu;
1157
1158 cr_tcpip.recv_list = rfl;
1159 cr_tcpip.close_list = cfl;
1160 if ( cr_tcpip.initialized )
1161 {
1162 return;
1163 }
1164
1165 cr_tcpip.initialized = 1;
1166
1167 cr_tcpip.num_conns = 0;
1168 cr_tcpip.conns = NULL;
1169
1170 cr_tcpip.server_sock = -1;
1171
1172#ifdef CHROMIUM_THREADSAFE
1173 crInitMutex(&cr_tcpip.mutex);
1174 crInitMutex(&cr_tcpip.recvmutex);
1175#endif
1176 cr_tcpip.bufpool = crBufferPoolInit(16);
1177}
1178
1179
1180/**
1181 * The function that actually connects. This should only be called by clients
1182 * Servers have another way to set up the socket.
1183 */
1184int
1185crTCPIPDoConnect( CRConnection *conn )
1186{
1187 int err;
1188#ifndef ADDRINFO
1189 struct sockaddr_in servaddr;
1190 struct hostent *hp;
1191 int i;
1192
1193 conn->tcp_socket = socket( AF_INET, SOCK_STREAM, 0 );
1194 if ( conn->tcp_socket < 0 )
1195 {
1196 int err = crTCPIPErrno( );
1197 crWarning( "socket error: %s", crTCPIPErrorString( err ) );
1198 cr_tcpip.conns[conn->index] = NULL; /* remove from table */
1199 return 0;
1200 }
1201
1202 if (SocketCreateCallback) {
1203 SocketCreateCallback(CR_SOCKET_CREATE, conn->tcp_socket);
1204 }
1205
1206 /* Set up the socket the way *we* want. */
1207 spankSocket( conn->tcp_socket );
1208
1209 /* Standard Berkeley sockets mumbo jumbo */
1210 hp = gethostbyname( conn->hostname );
1211 if ( !hp )
1212 {
1213 crWarning( "Unknown host: \"%s\"", conn->hostname );
1214 cr_tcpip.conns[conn->index] = NULL; /* remove from table */
1215 return 0;
1216 }
1217
1218 crMemset( &servaddr, 0, sizeof(servaddr) );
1219 servaddr.sin_family = AF_INET;
1220 servaddr.sin_port = htons( (short) conn->port );
1221
1222 crMemcpy((char *) &servaddr.sin_addr, hp->h_addr, sizeof(servaddr.sin_addr));
1223#else
1224 char port_s[NI_MAXSERV];
1225 struct addrinfo *res,*cur;
1226 struct addrinfo hints;
1227
1228 sprintf(port_s, "%u", (short unsigned) conn->port);
1229
1230 crMemset(&hints, 0, sizeof(hints));
1231 hints.ai_family = PF;
1232 hints.ai_socktype = SOCK_STREAM;
1233
1234 err = getaddrinfo( conn->hostname, port_s, &hints, &res);
1235 if ( err )
1236 {
1237 crWarning( "Unknown host: \"%s\": %s", conn->hostname, gai_strerror(err) );
1238 cr_tcpip.conns[conn->index] = NULL; /* remove from table */
1239 return 0;
1240 }
1241#endif
1242
1243 /* If brokered, we'll contact the mothership to broker the network
1244 * connection. We'll send the mothership our hostname, the port and
1245 * our endianness and will get in return a connection ID number.
1246 */
1247 if (conn->broker)
1248 {
1249 crError("There shouldn't be any brokered connections in VirtualBox");
1250 }
1251
1252#ifndef ADDRINFO
1253 for (i=1;i;)
1254#else
1255 for (cur=res;cur;)
1256#endif
1257 {
1258#ifndef ADDRINFO
1259
1260#ifdef RECV_BAIL_OUT
1261 err = sizeof(unsigned int);
1262 if ( getsockopt( conn->tcp_socket, SOL_SOCKET, SO_RCVBUF,
1263 (char *) &conn->krecv_buf_size, &err ) )
1264 {
1265 conn->krecv_buf_size = 0;
1266 }
1267#endif
1268 if ( !connect( conn->tcp_socket, (struct sockaddr *) &servaddr,
1269 sizeof(servaddr) ) )
1270 return 1;
1271#else
1272
1273 conn->tcp_socket = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
1274 if ( conn->tcp_socket < 0 )
1275 {
1276 int err = crTCPIPErrno( );
1277 if (err != EAFNOSUPPORT)
1278 crWarning( "socket error: %s, trying another way", crTCPIPErrorString( err ) );
1279 cur=cur->ai_next;
1280 continue;
1281 }
1282
1283 if (SocketCreateCallback) {
1284 SocketCreateCallback(CR_SOCKET_CREATE, conn->tcp_socket);
1285 }
1286
1287 err = 1;
1288 setsockopt(conn->tcp_socket, SOL_SOCKET, SO_REUSEADDR, &err, sizeof(int));
1289
1290 /* Set up the socket the way *we* want. */
1291 spankSocket( conn->tcp_socket );
1292
1293#if RECV_BAIL_OUT
1294 err = sizeof(unsigned int);
1295 if ( getsockopt( conn->tcp_socket, SOL_SOCKET, SO_RCVBUF,
1296 (char *) &conn->krecv_buf_size, &err ) )
1297 {
1298 conn->krecv_buf_size = 0;
1299 }
1300#endif
1301
1302 if ( !connect( conn->tcp_socket, cur->ai_addr, cur->ai_addrlen ) ) {
1303 freeaddrinfo(res);
1304 return 1;
1305 }
1306#endif
1307
1308 err = crTCPIPErrno( );
1309 if ( err == EADDRINUSE || err == ECONNREFUSED )
1310 crWarning( "Connection refused to %s:%d, %s",
1311 conn->hostname, conn->port, crTCPIPErrorString( err ) );
1312
1313 else if ( err == EINTR )
1314 {
1315 crWarning( "connection to %s:%d "
1316 "interrupted, trying again", conn->hostname, conn->port );
1317 continue;
1318 }
1319 else
1320 crWarning( "Couldn't connect to %s:%d, %s",
1321 conn->hostname, conn->port, crTCPIPErrorString( err ) );
1322 crCloseSocket( conn->tcp_socket );
1323#ifndef ADDRINFO
1324 i=0;
1325#else
1326 cur=cur->ai_next;
1327#endif
1328 }
1329#ifdef ADDRINFO
1330 freeaddrinfo(res);
1331 crWarning( "Couldn't find any suitable way to connect to %s", conn->hostname );
1332#endif
1333 cr_tcpip.conns[conn->index] = NULL; /* remove from table */
1334 return 0;
1335}
1336
1337
1338/**
1339 * Disconnect this connection, but don't free(conn).
1340 */
1341void
1342crTCPIPDoDisconnect( CRConnection *conn )
1343{
1344 int num_conns = cr_tcpip.num_conns;
1345 int none_left = 1;
1346 int i;
1347
1348 /* If this connection has already been disconnected (e.g.
1349 * if the connection has been lost and disabled through
1350 * a call to __tcpip_dead_connection(), which will then
1351 * call this routine), don't disconnect it again; if we
1352 * do, and if a new valid connection appears in the same
1353 * slot (conn->index), we'll effectively disable the
1354 * valid connection by mistake, leaving us unable to
1355 * receive inbound data on that connection.
1356 */
1357 if (conn->type == CR_NO_CONNECTION) return;
1358
1359 crCloseSocket( conn->tcp_socket );
1360 if (conn->hostname) {
1361 crFree(conn->hostname);
1362 conn->hostname = NULL;
1363 }
1364 conn->tcp_socket = 0;
1365 conn->type = CR_NO_CONNECTION;
1366 cr_tcpip.conns[conn->index] = NULL;
1367
1368 /* see if any connections remain */
1369 for (i = 0; i < num_conns; i++)
1370 {
1371 if ( cr_tcpip.conns[i] && cr_tcpip.conns[i]->type != CR_NO_CONNECTION )
1372 none_left = 0; /* found a live connection */
1373 }
1374
1375#if 0 /* disabled on 13 Dec 2005 by BrianP - this prevents future client
1376 * connections after the last one goes away.
1377 */
1378 if (none_left && cr_tcpip.server_sock != -1)
1379 {
1380 crDebug("Closing master socket (probably quitting).");
1381 crCloseSocket( cr_tcpip.server_sock );
1382 cr_tcpip.server_sock = -1;
1383#ifdef CHROMIUM_THREADSAFE
1384 crFreeMutex(&cr_tcpip.mutex);
1385 crFreeMutex(&cr_tcpip.recvmutex);
1386#endif
1387 crBufferPoolFree( cr_tcpip.bufpool );
1388 cr_tcpip.bufpool = NULL;
1389 last_port = 0;
1390 cr_tcpip.initialized = 0;
1391 }
1392#endif
1393}
1394
1395
1396/**
1397 * Initialize a CRConnection for tcp/ip. This is called via the
1398 * InitConnection() function (and from the UDP module).
1399 */
1400void
1401crTCPIPConnection( CRConnection *conn )
1402{
1403 int i, found = 0;
1404 int n_bytes;
1405
1406 CRASSERT( cr_tcpip.initialized );
1407
1408 conn->type = CR_TCPIP;
1409 conn->Alloc = crTCPIPAlloc;
1410 conn->Send = crTCPIPSend;
1411 conn->SendExact = crTCPIPWriteExact;
1412 conn->Recv = crTCPIPSingleRecv;
1413 conn->RecvMsg = crTCPIPReceiveMessage;
1414 conn->Free = crTCPIPFree;
1415 conn->Accept = crTCPIPAccept;
1416 conn->Connect = crTCPIPDoConnect;
1417 conn->Disconnect = crTCPIPDoDisconnect;
1418 conn->InstantReclaim = crTCPIPInstantReclaim;
1419 conn->HandleNewMessage = crTCPIPHandleNewMessage;
1420 conn->index = cr_tcpip.num_conns;
1421 conn->sizeof_buffer_header = sizeof( CRTCPIPBuffer );
1422 conn->actual_network = 1;
1423
1424 conn->krecv_buf_size = 0;
1425
1426 /* Find a free slot */
1427 for (i = 0; i < cr_tcpip.num_conns; i++) {
1428 if (cr_tcpip.conns[i] == NULL) {
1429 conn->index = i;
1430 cr_tcpip.conns[i] = conn;
1431 found = 1;
1432 break;
1433 }
1434 }
1435
1436 /* Realloc connection stack if we couldn't find a free slot */
1437 if (found == 0) {
1438 n_bytes = ( cr_tcpip.num_conns + 1 ) * sizeof(*cr_tcpip.conns);
1439 crRealloc( (void **) &cr_tcpip.conns, n_bytes );
1440 cr_tcpip.conns[cr_tcpip.num_conns++] = conn;
1441 }
1442}
1443
1444
1445int crGetHostname( char *buf, unsigned int len )
1446{
1447 const char *override;
1448 int ret;
1449
1450 override = crGetenv("CR_HOSTNAME");
1451 if (override)
1452 {
1453 crStrncpy(buf, override, len);
1454 ret = 0;
1455 }
1456 else
1457 ret = gethostname( buf, len );
1458 return ret;
1459}
1460
1461
1462CRConnection** crTCPIPDump( int *num )
1463{
1464 *num = cr_tcpip.num_conns;
1465
1466 return cr_tcpip.conns;
1467}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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