VirtualBox

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

Last change on this file since 69989 was 63199, checked in by vboxsync, 8 years ago

GuestHost/OpenGL: warnings (gcc).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use