diff for chromium of July 4th 2002 There are mainly 4 ideas in this patch : * ipv6 support * udptcpip support * "Barfing" support * mtu discovery support (hence rebuffering) I'll annotate each patch, telling which ideas it implements There are also some little corrections, which have nothing to do with these ideas * udptcpip, barf, mtu Just declaration 'buffer_size' will indeed be the buffer's size, which won't change (would be a headache, since old buffers can still be held by spus), but the network driver may tell the upper layers about the mtu in 'mtu' (see udptcpip.c) the packer or tilesort spus will hence have to check if it shrinked, just after sending data (that's when udptcp can detect mtu shrink) --- cr-04-07-02/include/cr_net.h Fri Jun 7 13:06:50 2002 +++ cr.bak/include/cr_net.h Thu Jul 4 13:36:40 2002 @@ -14,6 +14,7 @@ #endif #include +#include #include "cr_protocol.h" @@ -26,6 +27,7 @@ typedef enum { CR_NO_CONNECTION, CR_TCPIP, + CR_UDPTCPIP, CR_FILE, CR_GM, CR_DROP_PACKETS @@ -50,6 +52,7 @@ void crNetInit( CRNetReceiveFunc recvFunc, CRNetCloseFunc closeFunc ); void *crNetAlloc( CRConnection *conn ); void crNetSend( CRConnection *conn, void **bufp, void *start, unsigned int len ); +void crNetBarf( CRConnection *conn, void **bufp, void *start, unsigned int len ); void crNetSendExact( CRConnection *conn, void *start, unsigned int len ); void crNetSingleRecv( CRConnection *conn, void *buf, unsigned int len ); unsigned int crNetGetMessage( CRConnection *conn, CRMessage **message ); @@ -83,6 +86,7 @@ CRMultiBuffer multi; unsigned int mtu; + unsigned int buffer_size; int broker; @@ -93,6 +97,7 @@ void *(*Alloc)( CRConnection *conn ); void (*Send)( CRConnection *conn, void **buf, void *start, unsigned int len ); + void (*Barf)( CRConnection *conn, void **buf, void *start, unsigned int len ); void (*SendExact)( CRConnection *conn, void *start, unsigned int len ); void (*Recv)( CRConnection *conn, void *buf, unsigned int len ); void (*Free)( CRConnection *conn, void *buf ); @@ -115,6 +120,15 @@ /* TCP/IP */ CRSocket tcp_socket; int index; + + /* UDP/IP */ + CRSocket udp_socket; + struct sockaddr_storage remoteaddr; + + /* UDP/TCP/IP */ + unsigned int seq; + void *udp_packet; + int udp_packetlen; /* FILE Tracing */ enum { CR_FILE_WRITE, CR_FILE_READ } file_direction; * barf, mtu I added crPackCanHoldOpcode / Buffer so as not to have to modify every file if the buffer scheme changes (really avoids bugs) A pack buffer now has both a size and a mtu. the size limit normally is never reached (MTU can entirely hold in the data part, thanks to the countercomputing of packspu or tilesortspu when choosing the buffers' size) It also has status flags, whether it holds BeginEnd (hence will be barfed), and whether it *is* in a BeginEnd block. See the packing changes for their use. The canBarf field is indicated by the spu, when net->Barf is not NULL, so that supplementary flushing can be done only if needed (if we are connected to another server to which we can't barf, its buffer won't be flush that often) CounterComputing is somewhat yucky, only the mtu should be given to the packer, which would then compute the buffer size, but this buffer size must be passed back to the spu, to let it pass it to the net driver. Not clear how to correct it. Some opcodes which aren't in BeginEnd blocks, but are generally close to them can actually be barfed, such as Color or Translate (see packer.py), hence NO_BEGINEND_FLUSH version is used, to avoid barfing little blocks because silly little changes between BeginEnd blocks make the packer flush. diff -urN cr-04-07-02/include/cr_pack.h cr.bak/include/cr_pack.h --- cr-04-07-02/include/cr_pack.h Wed Jun 26 14:28:39 2002 +++ cr.bak/include/cr_pack.h Thu Jul 4 13:36:40 2002 @@ -29,9 +29,13 @@ typedef struct { void *pack; unsigned int size; + unsigned int mtu; unsigned char *data_start, *data_current, *data_end; unsigned char *opcode_start, *opcode_current, *opcode_end; GLboolean geometry_only; /* just used for debugging */ + GLboolean holds_BeginEnd; + GLboolean in_BeginEnd; + GLboolean canBarf; } CRPackBuffer; typedef void (*CRPackFlushFunc)(void *arg); @@ -58,8 +62,8 @@ void crPackSetBuffer( CRPackContext *pc, CRPackBuffer *buffer ); void crPackGetBuffer( CRPackContext *pc, CRPackBuffer *buffer ); -void crPackInitBuffer( CRPackBuffer *buffer, void *buf, int size, int extra ); -void crPackResetPointers( CRPackContext *pc, int extra ); +void crPackInitBuffer( CRPackBuffer *buffer, void *buf, int size, int mtu ); +void crPackResetPointers( CRPackContext *pc ); void crPackFlushFunc( CRPackContext *pc, CRPackFlushFunc ff ); void crPackFlushArg( CRPackContext *pc, void *flush_arg ); void crPackSendHugeFunc( CRPackContext *pc, CRPackSendHugeFunc shf ); @@ -71,6 +75,8 @@ void crPackAppendBuffer( CRPackBuffer *buffer ); void crPackAppendBoundedBuffer( CRPackBuffer *buffer, GLrecti *bounds ); +int crPackCanHoldOpcode( int num_opcode, int num_data ); +int crPackCanHoldBuffer( CRPackBuffer *buffer ); #if defined(LINUX) || defined(WINDOWS) #define CR_UNALIGNED_ACCESS_OKAY @@ -87,24 +93,31 @@ void SanityCheck(void); -#define GET_BUFFERED_POINTER( pc, len ) \ +#define GET_BUFFERED_POINTER_NO_BEGINEND_FLUSH( pc, len ) \ THREADASSERT( pc ); \ data_ptr = pc->buffer.data_current; \ - if (data_ptr + (len) > pc->buffer.data_end ) \ + if ( !crPackCanHoldOpcode( 1, (len) ) ) \ { \ pc->Flush( pc->flush_arg ); \ data_ptr = pc->buffer.data_current; \ - CRASSERT( data_ptr + (len) <= pc->buffer.data_end ); \ + CRASSERT(crPackCanHoldOpcode( 1, (len) ) ); \ } \ pc->buffer.data_current += (len) +#define GET_BUFFERED_POINTER( pc, len ) \ + if ( pc->buffer.holds_BeginEnd && ! pc->buffer.in_BeginEnd ) { \ + pc->Flush( pc->flush_arg ); \ + pc->buffer.holds_BeginEnd = 0; \ + } \ + GET_BUFFERED_POINTER_NO_BEGINEND_FLUSH( pc, len ) + #define GET_BUFFERED_COUNT_POINTER( pc, len ) \ data_ptr = pc->buffer.data_current; \ - if (data_ptr + (len) > pc->buffer.data_end ) \ + if ( !crPackCanHoldOpcode( 1, (len) ) ) \ { \ pc->Flush( pc->flush_arg ); \ data_ptr = pc->buffer.data_current; \ - CRASSERT( data_ptr + (len) <= pc->buffer.data_end ); \ + CRASSERT( crPackCanHoldOpcode( 1, (len) ) ); \ } \ pc->current.vtx_count++; \ pc->buffer.data_current += (len) * mtu this is for passing the buffer size to the net layer, for crAllocing later, along with the initial mtu. diff -urN cr-04-07-02/include/cr_server.h cr.bak/include/cr_server.h --- cr-04-07-02/include/cr_server.h Thu Jun 27 22:49:10 2002 +++ cr.bak/include/cr_server.h Thu Jul 4 13:36:40 2002 @@ -47,6 +47,7 @@ int useL2; int mtu; + int buffer_size; char protocol[1024]; unsigned int muralWidth, muralHeight; * little trivial correcting (nothing to do with the rest) diff -urN cr-04-07-02/mothership/client/client.c cr.bak/mothership/client/client.c --- cr-04-07-02/mothership/client/client.c Fri Jun 28 21:45:20 2002 +++ cr.bak/mothership/client/client.c Thu Jul 4 13:36:40 2002 @@ -19,8 +19,6 @@ CRConnection *crMothershipConnect( void ) { char *mother_server = NULL; - int mother_port = MOTHERPORT; - char mother_url[1024]; crNetInit( NULL, NULL ); @@ -31,9 +29,7 @@ mother_server = "localhost"; } - sprintf( mother_url, "%s:%d", mother_server, mother_port ); - - return crNetConnectToServer( mother_server, 10000, 8096, 0 ); + return crNetConnectToServer( mother_server, MOTHERPORT, 8096, 0 ); } void crMothershipDisconnect( CRConnection *conn ) * ipv6, udptcpip also be more verbose when saying "not connecting", when only the port is different diff -urN cr-04-07-02/mothership/server/mothership.py cr.bak/mothership/server/mothership.py --- cr-04-07-02/mothership/server/mothership.py Fri Jun 28 21:49:53 2002 +++ cr.bak/mothership/server/mothership.py Thu Jul 4 13:36:40 2002 @@ -114,14 +114,18 @@ """AddServer(node, protocol='tcpip', port=7000) Tells a client node where to find its server.""" node.Conf( 'port', port ) - if protocol == 'tcpip': - self.__add_server( node, "%s://%s:%d" % (protocol,node.ipaddr,port) ) - elif (protocol.startswith('file') or protocol.startswith('swapfile')): + #if protocol == 'tcpip': + # self.__add_server( node, "%s://%s:%d" % (protocol,node.ipaddr,port) ) + #elif ... + if (protocol.startswith('file') or protocol.startswith('swapfile')): self.__add_server( node, "%s" % protocol ) # Don't tell the server "node" about this. return else: self.__add_server( node, "%s://%s:%d" % (protocol,node.host,port) ) + # use this for tcp/ip : send hostname rather than ip + # (waiting for getaddrinfo, for probing which one is + # available) node.AddClient( self, protocol ) def TileLayoutFunction( self, layoutFunc ): @@ -160,7 +164,8 @@ self.host = host if (host == 'localhost'): self.host = socket.gethostname() - self.ipaddr = socket.gethostbyname(self.host) + #self.ipaddr = socket.gethostbyname(self.host) + # deleted (see above) # unqualify the hostname if it is already that way. # e.g., turn "foo.bar.baz" into "foo" @@ -470,43 +475,51 @@ This starts the mothership's event loop.""" CRInfo("This is Chromium, Version ALPHA") try: - HOST = "" - try: - s = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) - except: - Fatal( "Couldn't create socket" ); - - try: - s.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) - except: - Fatal( "Couldn't set the SO_REUSEADDR option on the socket!" ) - - try: - s.bind( (HOST, PORT) ) - except: - Fatal( "Couldn't bind to port %d" % PORT ); - - try: - s.listen(100) - except: - Fatal( "Couldn't listen!" ); - - self.all_sockets.append(s) - - # Start spawning processes for each node - # that has requested something be started. - spawner = CRSpawner( self.nodes ) ; - spawner.start() ; - - while 1: - ready = select.select( self.all_sockets, [], [], 0.1 )[0] - for sock in ready: - if sock == s: - conn, addr = s.accept() - self.wrappers[conn] = SockWrapper(conn) - self.all_sockets.append( conn ) - else: - self.ProcessRequest( self.wrappers[sock] ) + for res in socket.getaddrinfo(None, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): + af, socktype, proto, canonname, sa = res + + try: + s = socket.socket( af, socktype ) + except: + CRDebug( "Couldn't create socket of family %u, trying another one" % af ); + continue + + try: + s.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) + except: + CRDebug( "Couldn't set the SO_REUSEADDR option on the socket!" ) + continue + + try: + s.bind( sa ) + except: + CRDebug( "Couldn't bind to port %d" % PORT ); + continue + + try: + s.listen(100) + except: + CRDebug( "Couldn't listen!" ); + continue + + CRDebug( "Mothership ready" ); + self.all_sockets.append(s) + + # Start spawning processes for each node + # that has requested something be started. + spawner = CRSpawner( self.nodes ) ; + spawner.start() ; + + while 1: + ready = select.select( self.all_sockets, [], [], 0.1 )[0] + for sock in ready: + if sock == s: + conn, addr = s.accept() + self.wrappers[conn] = SockWrapper(conn) + self.all_sockets.append( conn ) + else: + self.ProcessRequest( self.wrappers[sock] ) + Fatal( "Couldn't find local TCP port" ) except KeyboardInterrupt: try: for sock in self.all_sockets: @@ -546,9 +559,9 @@ Connects the given socket.""" connect_info = args.split( " " ) protocol = connect_info[0] - if (protocol == 'tcpip'): + if (protocol == 'tcpip' or protocol == 'udptcpip'): (p, hostname, port_str, endianness_str) = connect_info - hostname = socket.gethostbyname(hostname) + #hostname = socket.gethostbyname(hostname) port = int(port_str) endianness = int(endianness_str) for server_sock in self.wrappers.values(): @@ -560,7 +573,7 @@ self.conn_id += 1 return else: - CRDebug( "not connecting to \"%s\" (!= \"%s\")" % (server_hostname, hostname) ) + CRDebug( "not connecting to \"%s:%d\" (!= \"%s:%d\")" % (server_hostname, server_port, hostname, port) ) sock.tcpip_connect_wait = (hostname, port, endianness) elif (protocol == 'gm'): (p, hostname, port_str, node_id_str, port_num_str, endianness_str) = connect_info @@ -585,9 +598,9 @@ Accepts the given socket.""" accept_info = args.split( " " ) protocol = accept_info[0] - if protocol == 'tcpip': + if protocol == 'tcpip' or protocol == 'udptcpip': (p, hostname, port_str, endianness_str) = accept_info - hostname = socket.gethostbyname(hostname) + #hostname = socket.gethostbyname(hostname) port = int(port_str) endianness = int(endianness_str) for client_sock in self.wrappers.values(): @@ -599,7 +612,7 @@ self.conn_id += 1 return else: - CRDebug( "not accepting from \"%s\" (!= \"%s\")" % (client_hostname, hostname ) ) + CRDebug( "not accepting from \"%s:%d\" (!= \"%s:%d\")" % (client_hostname, client_port, hostname, port ) ) sock.tcpip_accept_wait = (hostname, port, endianness) elif protocol == 'gm': * barf diff -urN cr-04-07-02/packer/Makefile cr.bak/packer/Makefile --- cr-04-07-02/packer/Makefile Tue Feb 19 16:19:18 2002 +++ cr.bak/packer/Makefile Thu Jul 4 13:36:40 2002 @@ -10,6 +10,7 @@ NORMAL_FILES = packer \ pack_arrays \ pack_bbox \ + pack_beginend \ pack_bounds \ pack_buffer \ pack_client \ * barf here we update the buffer's flags about BeginEnd, but only if it may be barfed. diff -urN cr-04-07-02/packer/pack_beginend.c cr.bak/packer/pack_beginend.c --- cr-04-07-02/packer/pack_beginend.c Thu Jan 1 01:00:00 1970 +++ cr.bak/packer/pack_beginend.c Thu Jul 4 13:41:12 2002 @@ -0,0 +1,67 @@ +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#include "packer.h" +#include "cr_protocol.h" + +void PACK_APIENTRY crPackBegin( GLenum mode ) +{ + GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + if (pc->buffer.canBarf) + { + if (!pc->buffer.holds_BeginEnd) + pc->Flush( pc->flush_arg ); + pc->buffer.in_BeginEnd = 1; + pc->buffer.holds_BeginEnd = 1; + } + GET_BUFFERED_POINTER( pc, 4 ); + pc->current.begin_data = data_ptr; + pc->current.begin_op = pc->buffer.opcode_current; + WRITE_DATA( 0, GLenum, mode ); + WRITE_OPCODE( pc, CR_BEGIN_OPCODE ); +} + +void PACK_APIENTRY crPackBeginSWAP( GLenum mode ) +{ + GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + if (pc->buffer.canBarf) + { + if (!pc->buffer.holds_BeginEnd) + pc->Flush( pc->flush_arg ); + pc->buffer.in_BeginEnd = 1; + pc->buffer.holds_BeginEnd = 1; + } + GET_BUFFERED_POINTER( pc, 4 ); + pc->current.begin_data = data_ptr; + pc->current.begin_op = pc->buffer.opcode_current; + WRITE_DATA( 0, GLenum, SWAP32(mode) ); + WRITE_OPCODE( pc, CR_BEGIN_OPCODE ); +} + +void PACK_APIENTRY crPackEnd( void ) +{ + GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + GET_BUFFERED_POINTER_NO_ARGS( pc ); + WRITE_OPCODE( pc, CR_END_OPCODE ); + pc->buffer.in_BeginEnd = 0; +} + +void PACK_APIENTRY crPackEndSWAP( void ) +{ + GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + GET_BUFFERED_POINTER_NO_ARGS( pc ); + WRITE_OPCODE( pc, CR_END_OPCODE ); + pc->buffer.in_BeginEnd = 0; +} + * mtu, barf overflow when barfing is not a problem : mtu shrinked, that's all before Reseting, we keep BeginEnd flags, for when a BeginEnd block is cut. The extra data is now useless: merely tinkering with mtu will be enough (see tilesortspu_flush.c) Please note len_aligned in crPackAppendBoundedBuffer: it was buggy without ! Furthermore, not only from (opcode_current+1) should it be copied, but from (opcode_current+1) & ~0x3, so that data will still be aligned. (and then, len_aligned will always be the same as length) diff -urN cr-04-07-02/packer/pack_buffer.c cr.bak/packer/pack_buffer.c --- cr-04-07-02/packer/pack_buffer.c Tue Apr 2 20:45:07 2002 +++ cr.bak/packer/pack_buffer.c Thu Jul 4 13:36:40 2002 @@ -61,18 +61,25 @@ pc->SendHuge = shf; } -void crPackResetPointers( CRPackContext *pc, int extra ) +void crPackResetPointers( CRPackContext *pc ) { const GLboolean g = pc->buffer.geometry_only; /* save this flag */ - crPackInitBuffer( &(pc->buffer), pc->buffer.pack, pc->buffer.size, extra ); + const GLboolean holds_BeginEnd = pc->buffer.holds_BeginEnd; + const GLboolean in_BeginEnd = pc->buffer.in_BeginEnd; + const GLboolean canBarf = pc->buffer.canBarf; + crPackInitBuffer( &(pc->buffer), pc->buffer.pack, pc->buffer.size, pc->buffer.mtu ); pc->buffer.geometry_only = g; /* restore the flag */ + pc->buffer.holds_BeginEnd = holds_BeginEnd; + pc->buffer.in_BeginEnd = in_BeginEnd; + pc->buffer.canBarf = canBarf; } -void crPackInitBuffer( CRPackBuffer *buf, void *pack, int size, int extra ) +void crPackInitBuffer( CRPackBuffer *buf, void *pack, int size, int mtu ) { unsigned int num_opcodes; buf->size = size; + buf->mtu = mtu; buf->pack = pack; /* Each opcode has at least a 1-word payload, so opcodes can occupy at most @@ -91,42 +98,81 @@ buf->opcode_current = buf->opcode_start; buf->opcode_end = buf->opcode_start - num_opcodes; - buf->data_end -= extra; /* caller may want extra space (sigh) */ - buf->geometry_only = GL_FALSE; + buf->holds_BeginEnd = 0; + buf->in_BeginEnd = 0; + buf->canBarf = 0; +} + +int crPackCanHoldOpcode( int num_opcode, int num_data ) +{ + GET_PACKER_CONTEXT(pc); + return (((pc->buffer.data_current - pc->buffer.opcode_current - 1 + + num_opcode + num_data + + 0x3 ) & ~0x3) + sizeof(CRMessageOpcodes) + <= pc->buffer.mtu + && pc->buffer.opcode_current - num_opcode >= pc->buffer.opcode_end + && pc->buffer.data_current + num_data <= pc->buffer.data_end ); +} + +int crPackCanHoldBuffer( CRPackBuffer *src ) +{ + int num_data = src->data_current - src->data_start; + int num_opcode = src->opcode_start - src->opcode_current; + return crPackCanHoldOpcode( num_opcode, num_data ); } void crPackAppendBuffer( CRPackBuffer *src ) { GET_PACKER_CONTEXT(pc); int num_data = src->data_current - src->data_start; - int num_opcode; + int num_opcode = src->opcode_start - src->opcode_current; + + if (!crPackCanHoldBuffer(src)) + { + if (src->holds_BeginEnd) + { + crWarning( "crPackAppendBuffer: overflowed the destination!" ); + return; + } + else + crError( "crPackAppendBuffer: overflowed the destination!" ); + } - if ( pc->buffer.data_current + num_data > pc->buffer.data_end ) - crError( "crPackAppendBuffer: overflowed the destination!" ); crMemcpy( pc->buffer.data_current, src->data_start, num_data ); pc->buffer.data_current += num_data; - num_opcode = src->opcode_start - src->opcode_current; CRASSERT( pc->buffer.opcode_current - num_opcode >= pc->buffer.opcode_end ); crMemcpy( pc->buffer.opcode_current + 1 - num_opcode, src->opcode_current + 1, num_opcode ); pc->buffer.opcode_current -= num_opcode; + pc->buffer.holds_BeginEnd |= src->holds_BeginEnd; + pc->buffer.in_BeginEnd = src->in_BeginEnd; } void crPackAppendBoundedBuffer( CRPackBuffer *src, GLrecti *bounds ) { GET_PACKER_CONTEXT(pc); - int length = src->data_current - ( src->opcode_current + 1 ); + int length = src->data_current - src->opcode_current - 1; + int len_aligned = (length + 3) & ~3; /* 24 is the size of the bounds-info packet... */ - if ( pc->buffer.data_current + length + 24 > pc->buffer.data_end ) - crError( "crPackAppendBoundedBuffer: overflowed the destination!" ); + if ( !crPackCanHoldOpcode( 1, len_aligned + 24 ) ) + { + if (src->holds_BeginEnd) { + crWarning( "crPackAppendBoundedBuffer: overflowed the destination!" ); + return; + } + else + crError( "crPackAppendBoundedBuffer: overflowed the destination!" ); + } crPackBoundsInfo( bounds, (GLbyte *) src->opcode_current + 1, length, src->opcode_start - src->opcode_current ); + pc->buffer.holds_BeginEnd |= src->holds_BeginEnd; + pc->buffer.in_BeginEnd = src->in_BeginEnd; } void *crPackAlloc( unsigned int size ) @@ -137,7 +183,7 @@ /* include space for the length and make the payload word-aligned */ size = ( size + sizeof(unsigned int) + 0x3 ) & ~0x3; - if ( pc->buffer.data_current + size <= pc->buffer.data_end ) + if ( crPackCanHoldOpcode( 1, size ) ) { /* we can just put it in the current buffer */ GET_BUFFERED_POINTER(pc, size ); @@ -146,7 +192,7 @@ { /* Okay, it didn't fit. Maybe it will after we flush. */ pc->Flush( pc->flush_arg ); - if ( pc->buffer.data_current + size <= pc->buffer.data_end ) + if ( crPackCanHoldOpcode( 1, size ) ) { GET_BUFFERED_POINTER(pc, size ); } * mtu, barf Begin / End are now in a separate file diff -urN cr-04-07-02/packer/packer.py cr.bak/packer/packer.py --- cr-04-07-02/packer/packer.py Wed Jul 3 23:24:07 2002 +++ cr.bak/packer/packer.py Thu Jul 4 13:36:40 2002 @@ -128,15 +128,6 @@ print "\tpc->current.%s.%s = data_ptr;" % (name,type) return - m = re.match( r"^(Begin)$", func_name ) - if m : - k = m.group(1) - name = '%s%s' % (k[:1].lower(),k[1:]) - type = "" - print "\tpc->current.%s_data = data_ptr;" % name - print "\tpc->current.%s_op = pc->buffer.opcode_current;" % name - return - for func_name in keys: ( return_type, arg_names, arg_types ) = gl_mapping[func_name] if stub_common.FindSpecial( "packer", func_name ): continue @@ -197,11 +188,14 @@ print "\tCRASSERT(!pc->buffer.geometry_only); /* sanity check */" if packet_length == 0: print "\tGET_BUFFERED_POINTER_NO_ARGS( pc );" + elif func_name[:9] == "Translate" or func_name[:5] == "Color": + if is_extended: + packet_length += 8 + print "\tGET_BUFFERED_POINTER_NO_BEGINEND_FLUSH( pc, %d );" % packet_length else: if is_extended: packet_length += 8 print "\tGET_BUFFERED_POINTER( pc, %d );" % packet_length - UpdateCurrentPointer( func_name ) counter = 0 * barf diff -urN cr-04-07-02/packer/packer_special cr.bak/packer/packer_special --- cr-04-07-02/packer/packer_special Tue Apr 2 20:45:07 2002 +++ cr.bak/packer/packer_special Thu Jul 4 13:36:40 2002 @@ -73,3 +73,5 @@ CombinerStageParameterfvNV ChromiumParametervCR crCreateWindow +Begin +End * mtu diff -urN cr-04-07-02/progs/packperf/packperf.c cr.bak/progs/packperf/packperf.c --- cr-04-07-02/progs/packperf/packperf.c Tue Apr 2 20:45:10 2002 +++ cr.bak/progs/packperf/packperf.c Thu Jul 4 13:36:40 2002 @@ -16,7 +16,7 @@ void reset_buffer( void *arg ) { - crPackResetPointers( pack_context, 0 ); + crPackResetPointers( pack_context ); UNUSED(arg); } @@ -53,7 +53,7 @@ CRPackBuffer pack_buffer; pack_context = crPackNewContext( 0 ); /* Don't swap bytes, for God's sake */ crPackSetContext( pack_context ); - crPackInitBuffer( &pack_buffer, crAlloc( 1024*1024 ), 1024*1024, 0 ); + crPackInitBuffer( &pack_buffer, crAlloc( 1024*1024 ), 1024*1024, 1024*1024 ); crPackSetBuffer( pack_context, &pack_buffer ); crPackFlushFunc( pack_context, reset_buffer ); * mtu here are examples of checking mtu size just after sending, and updating spu's own mtu size. diff -urN cr-04-07-02/spu/binaryswap/binaryswapspu.c cr.bak/spu/binaryswap/binaryswapspu.c --- cr-04-07-02/spu/binaryswap/binaryswapspu.c Wed Jul 3 02:42:28 2002 +++ cr.bak/spu/binaryswap/binaryswapspu.c Thu Jul 4 13:36:40 2002 @@ -289,11 +289,15 @@ crNetGetMessage( binaryswap_spu.peer_recv[i], &incoming_msg); crNetSend( binaryswap_spu.peer_send[i], NULL, binaryswap_spu.outgoing_msg, (width[i]*height[i]*4) + binaryswap_spu.offset); + if (binaryswap_spu.mtu > binaryswap_spu.peer_send[i]->mtu) + binaryswap_spu.mtu = binaryswap_spu.peer_send[i]->mtu; } /* higher of pair => send,recv */ else{ crNetSend( binaryswap_spu.peer_send[i], NULL, binaryswap_spu.outgoing_msg, (width[i]*height[i]*4) + binaryswap_spu.offset); + if (binaryswap_spu.mtu > binaryswap_spu.peer_send[i]->mtu) + binaryswap_spu.mtu = binaryswap_spu.peer_send[i]->mtu; crNetGetMessage( binaryswap_spu.peer_recv[i], &incoming_msg); } @@ -346,12 +350,16 @@ crNetGetMessage( binaryswap_spu.peer_recv[i], &incoming_msg); crNetSend( binaryswap_spu.peer_send[i], NULL, binaryswap_spu.outgoing_msg, width[i]*height[i]*(3+4) + binaryswap_spu.offset); + if (binaryswap_spu.mtu > binaryswap_spu.peer_send[i]->mtu) + binaryswap_spu.mtu = binaryswap_spu.peer_send[i]->mtu; } /* higher of pair => send,recv */ else{ crNetSend( binaryswap_spu.peer_send[i], NULL, binaryswap_spu.outgoing_msg, width[i]*height[i]*(3+4) + binaryswap_spu.offset); + if (binaryswap_spu.mtu > binaryswap_spu.peer_send[i]->mtu) + binaryswap_spu.mtu = binaryswap_spu.peer_send[i]->mtu; crNetGetMessage( binaryswap_spu.peer_recv[i], &incoming_msg); } * mtu diff -urN cr-04-07-02/spu/comm/commspu.c cr.bak/spu/comm/commspu.c --- cr-04-07-02/spu/comm/commspu.c Tue Apr 2 20:45:11 2002 +++ cr.bak/spu/comm/commspu.c Thu Jul 4 13:36:40 2002 @@ -23,6 +23,8 @@ comm_spu.msg->header.type = CR_MESSAGE_OOB; comm_spu.msg->frame_counter = frame_counter; crNetSend( comm_spu.peer_send, NULL, comm_spu.msg, comm_spu.num_bytes ); + if (comm_spu.mtu > comm_spu.peer_send->mtu) + comm_spu.mtu = comm_spu.peer_send->mtu; crNetGetMessage( comm_spu.peer_recv, &incoming_msg ); ping = (CommSPUPing *) incoming_msg; * mtu diff -urN cr-04-07-02/spu/hiddenline/hiddenlinespu_buffer.c cr.bak/spu/hiddenline/hiddenlinespu_buffer.c --- cr-04-07-02/spu/hiddenline/hiddenlinespu_buffer.c Tue Apr 2 20:45:12 2002 +++ cr.bak/spu/hiddenline/hiddenlinespu_buffer.c Thu Jul 4 13:36:40 2002 @@ -19,7 +19,7 @@ { buf = crAlloc( hiddenline_spu.buffer_size ); } - crPackInitBuffer( &(hiddenline_spu.pack_buffer), buf, hiddenline_spu.buffer_size, 0 ); + crPackInitBuffer( &(hiddenline_spu.pack_buffer), buf, hiddenline_spu.buffer_size, hiddenline_spu.buffer_size ); crPackSetBuffer( hiddenline_spu.packer, &(hiddenline_spu.pack_buffer) ); } * barf diff -urN cr-04-07-02/spu/pack/Makefile cr.bak/spu/pack/Makefile --- cr-04-07-02/spu/pack/Makefile Tue Jul 2 12:27:11 2002 +++ cr.bak/spu/pack/Makefile Thu Jul 4 13:36:40 2002 @@ -8,6 +8,7 @@ SHARED = 1 LIBRARY = packspu FILES = packspu \ + packspu_beginend \ packspu_client \ packspu_config \ packspu_context \ @@ -45,3 +46,7 @@ packspu_pixel.c: packspu_pixel.py packspu_pixel_special @$(ECHO) Building the Pack SPU Pixel functions @$(PYTHON) packspu_pixel.py > $@ + +packspu_beginend.c: packspu_beginend.py packspu_vertex_special + @$(ECHO) Building the Pack SPU Vertex functions + @$(PYTHON) packspu_beginend.py > $@ * barf: vertexes operation will take care about barfing: for example, in a TRIANGLES BeginEnd block, we want vertex to be grouped 3 by 3, so that they will be lost together, or else we get very nasty result if a non 3-divisible number of vertexes is lost, hence unsynchronising packer and unpacker ! diff -urN cr-04-07-02/spu/pack/pack.py cr.bak/spu/pack/pack.py --- cr-04-07-02/spu/pack/pack.py Tue Feb 19 16:19:21 2002 +++ cr.bak/spu/pack/pack.py Thu Jul 4 13:36:40 2002 @@ -50,6 +50,7 @@ stub_common.FindSpecial( "packspu_pixel", func_name ) or stub_common.FindSpecial( "packspu_flush", func_name ) or stub_common.FindSpecial( "packspu_client", func_name ) or + stub_common.FindSpecial( "packspu_vertex", func_name ) or stub_common.FindSpecial( "../../packer/packer_get", func_name )): pack_specials.append( func_name ) * barf diff -urN cr-04-07-02/spu/pack/packspu.h cr.bak/spu/pack/packspu.h --- cr-04-07-02/spu/pack/packspu.h Mon May 27 17:35:10 2002 +++ cr.bak/spu/pack/packspu.h Thu Jul 4 13:36:40 2002 @@ -28,6 +28,10 @@ unsigned long id; CRNetServer server; CRPackBuffer buffer; + CRPackBuffer normBuffer; + CRPackBuffer BeginEndBuffer; + GLenum BeginEndMode; + int BeginEndState; ContextInfo *currentContext; CRPackContext *packer; int writeback; * barf I keep 1 to 3 vertexes description while the figure is being traced in BeginEndBuffer, which I copy back into geometry buffer when it is complete. It may be quite heavy, though. diff -urN cr-04-07-02/spu/pack/packspu_beginend.py cr.bak/spu/pack/packspu_beginend.py --- cr-04-07-02/spu/pack/packspu_beginend.py +++ cr.bak/spu/pack/packspu_beginend.py @@ -0,0 +1,150 @@ +# Copyright (c) 2001, Stanford University +# All rights reserved. +# +# See the file LICENSE.txt for information on redistributing this software. + +import sys,os; +import cPickle; +import string; +import re; + +sys.path.append( "../../opengl_stub" ) +parsed_file = open( "../../glapi_parser/gl_header.parsed", "rb" ) +gl_mapping = cPickle.load( parsed_file ) + +import stub_common; + +keys = gl_mapping.keys() +keys.sort(); + +stub_common.CopyrightC() + +print """/* DO NOT EDIT - AUTOMATICALLY GENERATED BY packspu_beginend.py */ +#include "packspu.h" +#include "assert.h" +#include "cr_packfunctions.h" + +void PACKSPU_APIENTRY packspu_Begin( GLenum mode ) +{ + GET_THREAD(thread); + CRPackBuffer *buf = &thread->BeginEndBuffer; + + CRASSERT( mode >= GL_POINTS && mode <= GL_POLYGON ); + + if (pack_spu.swap) + { + crPackBeginSWAP( mode ); + } + else + { + crPackBegin( mode ); + } + + if ( thread->server.conn->Barf ) { + thread->BeginEndMode = mode; + thread->BeginEndState = -1; + if ( mode == GL_LINES || mode == GL_TRIANGLES || mode == GL_QUADS || mode == GL_POLYGON ) + { + CRASSERT(!buf->pack); + crPackGetBuffer( thread->packer, &thread->normBuffer ); + buf->pack = crNetAlloc( thread->server.conn ); + crPackInitBuffer( buf, buf->pack, thread->server.conn->buffer_size, thread->server.conn->mtu ); + crPackSetBuffer( thread->packer, buf ); + + thread->BeginEndState = 0; + } + } +} + +void PACKSPU_APIENTRY packspu_End( void ) +{ + GET_THREAD(thread); + CRPackBuffer *buf = &thread->BeginEndBuffer; + + if ( thread->server.conn->Barf && + (thread->BeginEndMode == GL_LINES + || thread->BeginEndMode == GL_TRIANGLES + || thread->BeginEndMode == GL_QUADS + || thread->BeginEndMode == GL_POLYGON ) ) + { + CRASSERT(buf->pack); + + crPackGetBuffer( thread->packer, buf ); + crPackSetBuffer( thread->packer, &thread->normBuffer ); + if ( !crPackCanHoldBuffer( buf ) ) + packspuFlush( (void *) thread ); + + crPackAppendBuffer( buf ); + crNetFree( thread->server.conn, buf->pack ); + buf->pack = NULL; + } + + if (pack_spu.swap) + { + crPackEndSWAP(); + } + else + { + crPackEnd(); + } +} + +static void DoVertex( void ) +{ + GET_THREAD(thread); + CRPackBuffer *buf = &thread->BeginEndBuffer; + CRPackBuffer *gbuf = &thread->normBuffer; + int num_data; + int num_opcode; + + //crDebug( "really doing Vertex" ); + crPackGetBuffer( thread->packer, buf ); + num_data = buf->data_current - buf->data_start; + num_opcode = buf->opcode_start - buf->opcode_current; + crPackSetBuffer( thread->packer, gbuf ); + if ( !crPackCanHoldBuffer( buf ) ) + // doesn't hold, first flush gbuf + packspuFlush( (void *) thread ); + + crPackAppendBuffer( buf ); + crPackGetBuffer( thread->packer, gbuf ); + crPackSetBuffer( thread->packer, buf ); + crPackResetPointers(thread->packer); +} + +static void RunState( void ) +{ + GET_THREAD(thread); + if (! thread->server.conn->Barf ) return; + if (thread->BeginEndState == -1) return; + switch(thread->BeginEndMode) { + case GL_POLYGON: + return; + case GL_LINES: + if ((thread->BeginEndState=(thread->BeginEndState+1)%2)) return; + break; + case GL_TRIANGLES: + if ((thread->BeginEndState=(thread->BeginEndState+1)%3)) return; + break; + case GL_QUADS: + if ((thread->BeginEndState=(thread->BeginEndState+1)%4)) return; + break; + } + DoVertex(); +} +""" + +for func_name in stub_common.AllSpecials( "packspu_vertex" ): + (return_type, args, types) = gl_mapping[func_name] + print 'void PACKSPU_APIENTRY packspu_%s%s' % ( func_name, stub_common.ArgumentString( args, types ) ) + print '{' + print '\tif (pack_spu.swap)' + print '\t{' + print '\t\tcrPack%sSWAP%s;' % ( func_name, stub_common.CallString( args ) ) + print '\t}' + print '\telse' + print '\t{' + print '\t\tcrPack%s%s;' % ( func_name, stub_common.CallString( args ) ) + print '\t}' + print '\tRunState();' + print '}' * mtu this countercomputing should be killed ! (see above) diff -urN cr-04-07-02/spu/pack/packspu_config.c cr.bak/spu/pack/packspu_config.c --- cr-04-07-02/spu/pack/packspu_config.c Tue Apr 30 12:24:56 2002 +++ cr.bak/spu/pack/packspu_config.c Thu Jul 4 13:36:40 2002 @@ -64,6 +64,10 @@ crMothershipGetMTU( conn, response ); sscanf( response, "%d", &(pack_spu.buffer_size) ); + /* get a buffer which can hold one big big opcode (counter computing + * against packer/pack_buffer.c) */ + pack_spu.buffer_size = ((((pack_spu.buffer_size - sizeof(CRMessageOpcodes)) * 5 + 3) / 4 + 0x03) & ~0x03) + sizeof(CRMessageOpcodes); + crSPUPropogateGLLimits( conn, pack_spu.id, child_spu, &pack_spu.limits ); crMothershipDisconnect( conn ); * mtu diff -urN cr-04-07-02/spu/pack/packspu_context.c cr.bak/spu/pack/packspu_context.c --- cr-04-07-02/spu/pack/packspu_context.c Tue Jul 2 12:27:11 2002 +++ cr.bak/spu/pack/packspu_context.c Thu Jul 4 13:36:40 2002 @@ -55,7 +55,8 @@ thread->packer = crPackNewContext( pack_spu.swap ); CRASSERT(thread->packer); crPackInitBuffer( &(thread->buffer), crNetAlloc(thread->server.conn), - thread->server.buffer_size, 0 ); + thread->server.conn->buffer_size, thread->server.conn->mtu ); + thread->buffer.canBarf = thread->server.conn->Barf?GL_TRUE:GL_FALSE; crPackSetBuffer( thread->packer, &thread->buffer ); crPackFlushFunc( thread->packer, packspuFlush ); crPackFlushArg( thread->packer, (void *) thread ); * mtu, barf holds_BeginEnd is only set when net->Barf is not NULL, so this is safe. diff -urN cr-04-07-02/spu/pack/packspu_net.c cr.bak/spu/pack/packspu_net.c --- cr-04-07-02/spu/pack/packspu_net.c Tue Apr 2 20:45:12 2002 +++ cr.bak/spu/pack/packspu_net.c Thu Jul 4 13:36:40 2002 @@ -167,7 +167,7 @@ */ /* XXX these calls seem to help, but might be appropriate */ crPackSetBuffer( thread->packer, buf ); - crPackResetPointers(thread->packer, 0); + crPackResetPointers(thread->packer); return; } @@ -175,12 +175,19 @@ CRASSERT( thread->server.conn ); - crNetSend( thread->server.conn, &(buf->pack), hdr, len ); + if ( buf->holds_BeginEnd ) + crNetBarf( thread->server.conn, &(buf->pack), hdr, len ); + else + crNetSend( thread->server.conn, &(buf->pack), hdr, len ); buf->pack = crNetAlloc( thread->server.conn ); + if ( buf->mtu > thread->server.conn->mtu ) + buf->mtu = thread->server.conn->mtu; + crPackSetBuffer( thread->packer, buf ); - crPackResetPointers(thread->packer, 0); /* don't need extra room like tilesort */ + + crPackResetPointers(thread->packer); (void) arg; } * barf diff -urN cr-04-07-02/spu/pack/packspu_special cr.bak/spu/pack/packspu_special --- cr-04-07-02/spu/pack/packspu_special Fri Jun 21 16:40:35 2002 +++ cr.bak/spu/pack/packspu_special Thu Jul 4 13:36:40 2002 @@ -30,3 +30,5 @@ crCreateWindow MakeCurrent DestroyContext +Begin +End * barf diff -urN cr-04-07-02/spu/pack/packspu_vertex_special cr.bak/spu/pack/packspu_vertex_special --- cr-04-07-02/spu/pack/packspu_vertex_special Thu Jan 1 01:00:00 1970 +++ cr.bak/spu/pack/packspu_vertex_special Thu Jul 4 13:36:40 2002 @@ -0,0 +1,28 @@ +# Copyright (c) 2001, Stanford University +# All rights reserved. +# +# See the file LICENSE.txt for information on redistributing this software. +Vertex2d +Vertex2dv +Vertex2f +Vertex2fv +Vertex2i +Vertex2iv +Vertex2s +Vertex2sv +Vertex3d +Vertex3dv +Vertex3f +Vertex3fv +Vertex3i +Vertex3iv +Vertex3s +Vertex3sv +Vertex4d +Vertex4dv +Vertex4f +Vertex4fv +Vertex4i +Vertex4iv +Vertex4s +Vertex4sv * be a little bit more verbose : tell about returned values diff -urN cr-04-07-02/spu/print/print.py cr.bak/spu/print/print.py --- cr-04-07-02/spu/print/print.py Wed Jul 3 23:24:07 2002 +++ cr.bak/spu/print/print.py Thu Jul 4 13:36:40 2002 @@ -113,11 +113,19 @@ print '%s )\\n"%s );' % ( printfstr, argstr ) print '\tfflush( print_spu.fp );' - if return_type != "void": - print '\treturn', + if return_type == "GLint": + print '\t{' + print '\t\tint res =', else: - print '\t', + if return_type != "void": + print '\treturn', + else: + print '\t', print 'print_spu.passthrough.%s%s;' % ( func_name, stub_common.CallString( names ) ) + if return_type == "GLint": + print '\t\tfprintf( print_spu.fp, "= %d\\n", res);' + print '\t\treturn res;' + print '\t}' print '}' print 'SPUNamedFunctionTable print_table[] = {' * be a little bit more verbose : tell which BeginEnd bloc type it is should be renumbered, though diff -urN cr-04-07-02/spu/print/printspu_enums.c cr.bak/spu/print/printspu_enums.c --- cr-04-07-02/spu/print/printspu_enums.c Sat Aug 25 02:17:46 2001 +++ cr.bak/spu/print/printspu_enums.c Thu Jul 4 13:36:40 2002 @@ -14,7 +14,7 @@ } GLT_enum_tab_ent; static GLT_enum_tab_ent __enum_tab_ents[256] = { - {0, 2},{2, 5},{7, 8},{15, 9},{24, 13},{37, 6},{43, 5},{48, 8},{56, 2}, + {1442, 10},{2, 5},{7, 8},{15, 9},{24, 13},{37, 6},{43, 5},{48, 8},{56, 2}, {58, 2},{60, 3},{63, 243},{306, 246},{552, 245},{-1, -1},{-1, -1}, {797, 6},{803, 3},{806, 10},{816, 2},{818, 11},{829, 16},{845, 4}, {849, 3},{852, 3},{855, 11},{866, 1},{867, 3},{870, 3},{873, 2},{875, 4}, @@ -1494,6 +1494,16 @@ "GL_OBJECT_POINT_SGIS", /* 0x81f5 */ "GL_EYE_LINE_SGIS", /* 0x81f6 */ "GL_OBJECT_LINE_SGIS", /* 0x81f7 */ + "GL_POINTS", /* 0x0000 */ + "GL_LINES", /* 0x0001 */ + "GL_LINE_LOOP", /* 0x0002 */ + "GL_LINE_STRIP", /* 0x0003 */ + "GL_TRIANGLES", /* 0x0004 */ + "GL_TRIANGLE_STRIP", /* 0x0005 */ + "GL_TRIANGLE_FAN", /* 0x0006 */ + "GL_QUADS", /* 0x0007 */ + "GL_QUAD_STRIP", /* 0x0008 */ + "GL_POLYGON", /* 0x0009 */ }; char * printspuEnumToStr(GLenum value) * mtu diff -urN cr-04-07-02/spu/tilesort/tilesortspu.h cr.bak/spu/tilesort/tilesortspu.h --- cr-04-07-02/spu/tilesort/tilesortspu.h Mon Jul 1 22:33:21 2002 +++ cr.bak/spu/tilesort/tilesortspu.h Thu Jul 4 13:36:40 2002 @@ -104,6 +104,7 @@ float widthScale, heightScale; /* muralSize / windowSize */ unsigned int MTU; + unsigned int buffer_size; int num_servers; TileSortSPUServer *servers; * mtu diff -urN cr-04-07-02/spu/tilesort/tilesortspu_config.c cr.bak/spu/tilesort/tilesortspu_config.c --- cr-04-07-02/spu/tilesort/tilesortspu_config.c Mon Jul 1 22:33:21 2002 +++ cr.bak/spu/tilesort/tilesortspu_config.c Thu Jul 4 13:36:40 2002 @@ -163,6 +163,10 @@ sscanf( response, "%d", &tilesort_spu.MTU ); crDebug( "Got the MTU as %d", tilesort_spu.MTU ); + /* get a buffer which can hold one big big opcode (counter computing + * against packer/pack_buffer.c) */ + tilesort_spu.buffer_size = ((((tilesort_spu.MTU - sizeof(CRMessageOpcodes) ) * 5 + 3) / 4 + 0x3) & ~0x3) + sizeof(CRMessageOpcodes); + tilesortspuGetTileInformation(conn); tilesortspuComputeRowsColumns(); @@ -227,7 +231,7 @@ crDebug( "Server %d: %s", i+1, server_url ); thread0->net[i].name = crStrdup( server_url ); - thread0->net[i].buffer_size = tilesort_spu.MTU; + thread0->net[i].buffer_size = tilesort_spu.buffer_size; if (!crMothershipGetTiles( conn, response, i )) { * mtu, barf since there is plenty of space, we don't need to care about FLUFF any more, MTU will reserve it, since we shrink it for the geometry buffer. (we reenlarge it when End is indeed packed, see tilesortspu_flush.c) diff -urN cr-04-07-02/spu/tilesort/tilesortspu_context.c cr.bak/spu/tilesort/tilesortspu_context.c --- cr-04-07-02/spu/tilesort/tilesortspu_context.c Thu Jun 27 20:10:08 2002 +++ cr.bak/spu/tilesort/tilesortspu_context.c Thu Jul 4 13:36:40 2002 @@ -20,17 +20,7 @@ { int i; - /* We need to mess with the pack size of the geometry buffer, since we - * may be using BoundsInfo packes, etc, etc. This is yucky. */ - thread->geom_pack_size = tilesort_spu.MTU; - thread->geom_pack_size -= sizeof( CRMessageOpcodes ); - thread->geom_pack_size -= 4; - - /* We need to shrink everything to fit in the DATA part of the server's send - * buffer since we're going to always send geometry as a BOUNDS_INFO - * packet. */ - thread->geom_pack_size = (thread->geom_pack_size * 4) / 5; - thread->geom_pack_size -= (24 + 1); /* 24 is the size of the BoundsInfo packet */ + thread->geom_pack_size = tilesort_spu.buffer_size; thread->pinchState.numRestore = 0; thread->pinchState.wind = 0; @@ -43,7 +33,11 @@ crPackSetContext( thread->packer ); /* sets the packer's per-thread context */ crPackInitBuffer( &(thread->geometry_pack), crAlloc( thread->geom_pack_size ), - thread->geom_pack_size, END_FLUFF ); + thread->geom_pack_size, tilesort_spu.MTU-(24+END_FLUFF+4+4)); + /* 24 is the size of the bounds info packet */ + /* END_FLUFF is the size of data of End */ + /* 4 since BoundsInfo opcode may take a whole 4 bytes */ + /* and 4 to let room for extra End's opcode, if needed */ thread->geometry_pack.geometry_only = GL_TRUE; crPackSetBuffer( thread->packer, &(thread->geometry_pack) ); crPackFlushFunc( thread->packer, tilesortspuFlush_callback ); @@ -55,8 +49,16 @@ CRASSERT(tilesort_spu.num_servers > 0); for (i = 0; i < tilesort_spu.num_servers; i++) + { crPackInitBuffer( &(thread->pack[i]), crNetAlloc( thread->net[i].conn ), - thread->net[i].buffer_size, 0 ); + thread->net[i].conn->buffer_size, thread->net[i].conn->mtu ); + if (thread->net[i].conn->Barf) + { + thread->pack[i].canBarf = GL_TRUE; + thread->packer->buffer.canBarf = GL_TRUE; + thread->geometry_pack.canBarf = GL_TRUE; + } + } thread->currentContext = NULL; @@ -86,9 +88,11 @@ for (i = 0; i < tilesort_spu.num_servers; i++) { thread->net[i].name = crStrdup( tilesort_spu.thread[0].net[i].name ); - thread->net[i].buffer_size = tilesort_spu.MTU; + thread->net[i].buffer_size = tilesort_spu.thread[0].net[i].buffer_size; /* Establish new connection to server[i] */ crNetNewClient( tilesort_spu.thread[0].net[i].conn, &(thread->net[i])); + if (tilesort_spu.MTU > thread->net[i].conn->mtu) + tilesort_spu.MTU = thread->net[i].conn->mtu; } tilesortspuInitThreadPacking( thread ); * mtu, barf we here reenlarge MTU to pack End it's here that we detect MTU shrink the same bug as in pack_buffer.c appears here when checking length before crPackAppendBoundedBuffering. diff -urN cr-04-07-02/spu/tilesort/tilesortspu_flush.c cr.bak/spu/tilesort/tilesortspu_flush.c --- cr-04-07-02/spu/tilesort/tilesortspu_flush.c Mon Jul 1 22:33:21 2002 +++ cr.bak/spu/tilesort/tilesortspu_flush.c Thu Jul 4 14:06:15 2002 @@ -73,18 +73,23 @@ hdr = __applySendBufferHeader( pack, &len ); - crNetSend( net->conn, &pack->pack, hdr, len ); - crPackInitBuffer( pack, crNetAlloc( net->conn ), pack->size, END_FLUFF ); + if ( pack->holds_BeginEnd ) + crNetBarf( net->conn, &pack->pack, hdr, len ); + else + crNetSend( net->conn, &pack->pack, hdr, len ); + + crPackInitBuffer( pack, crNetAlloc( net->conn ), net->conn->buffer_size, net->conn->mtu ); + pack->canBarf = net->conn->Barf ? GL_TRUE : GL_FALSE; } static void __appendBuffer( CRPackBuffer *src ) { GET_THREAD(thread); - int num_data = src->data_current - src->data_start; /*crWarning( "In __appendBuffer: %d bytes left, packing %d bytes", thread->packer->buffer.data_end - thread->packer->buffer.data_current, num_data ); */ - if ( thread->packer->buffer.data_current + num_data > thread->packer->buffer.data_end ) + if ( !crPackCanHoldBuffer(src) + || thread->packer->buffer.holds_BeginEnd ^ src->holds_BeginEnd) { /* No room to append -- send now */ @@ -100,17 +105,18 @@ void __appendBoundedBuffer( CRPackBuffer *src, GLrecti *bounds ) { GET_THREAD(thread); - /* 24 is the size of the bounds info packet */ - int num_data = src->data_current - src->opcode_current - 1 + 24; + int length = ((src->data_current - src->opcode_current - 1) + 3) & ~3; - if (num_data == 24) + if (length == 0) { /* nothing to send. */ return; } - if ( thread->packer->buffer.data_current + num_data > thread->packer->buffer.data_end ) + /* 24 is the size of the bounds info packet */ + if ( !crPackCanHoldOpcode( 1, length + 24 ) + || thread->packer->buffer.holds_BeginEnd ^ src->holds_BeginEnd) { /* No room to append -- send now */ tilesortspuSendServerBuffer( thread->state_server_index ); @@ -353,7 +359,7 @@ /* First, test to see if this is a big packet. */ - if (thread->packer->buffer.size > thread->net[0].conn->mtu ) + if (thread->packer->buffer.size > tilesort_spu.buffer_size ) { crDebug( "It was a big packet!" ); big_packet_hdr = __applySendBufferHeader( &(thread->packer->buffer), &big_packet_len ); @@ -416,7 +422,7 @@ if ( thread->currentContext->State->current.inBeginEnd ) { /*crDebug( "Closing this Begin/end!!!" ); */ - thread->packer->buffer.data_end += END_FLUFF; + thread->packer->buffer.mtu += END_FLUFF + 4; /* 4 for opcode */ if (tilesort_spu.swap) { crPackEndSWAP(); @@ -523,20 +529,31 @@ thread->state_server = NULL; thread->state_server_index = -1; + for ( i = 0 ; i < tilesort_spu.num_servers; i++ ) + { + if (thread->pack[i].mtu > thread->net[i].conn->mtu) + thread->pack[i].mtu = thread->net[i].conn->mtu; + if (tilesort_spu.MTU > thread->net[i].conn->mtu) + tilesort_spu.MTU = thread->net[i].conn->mtu; + } if ( big_packet_hdr != NULL ) { /* Throw away the big packet and make a new, smaller one */ crDebug( "Throwing away the big packet" ); crFree( thread->geometry_pack.pack ); - crPackInitBuffer( &(thread->geometry_pack), crAlloc( thread->geom_pack_size ), - thread->geom_pack_size, END_FLUFF ); + crPackInitBuffer( &(thread->geometry_pack), crAlloc( thread->geom_pack_size ), + thread->geom_pack_size, tilesort_spu.MTU - (24+END_FLUFF+8) ); + + /* 24 is the size of the bounds info packet */ + /* and 8 since End and BoundInfo opcodes may indeed take this space */ } else { /*crDebug( "Reverting to the old geometry buffer" ); */ + thread->geometry_pack.mtu = tilesort_spu.MTU - (24+END_FLUFF+8); crPackSetBuffer( thread->packer, &(thread->geometry_pack ) ); - crPackResetPointers( thread->packer, END_FLUFF ); + crPackResetPointers( thread->packer ); } /*crDebug( "Resetting the current vertex count and friends" ); */ @@ -609,7 +626,7 @@ crPackInitBuffer( &(thread->geometry_pack), crAlloc( thread->geometry_pack.size << 1 ), - thread->geometry_pack.size << 1, END_FLUFF ); + thread->geometry_pack.size << 1, (thread->geometry_pack.size << 1) - (24+END_FLUFF+8) ); thread->geometry_pack.geometry_only = GL_TRUE; crPackSetBuffer( thread->packer, &(thread->geometry_pack) ); * mtu diff -urN cr-04-07-02/spu/tilesort/tilesortspu_init.c cr.bak/spu/tilesort/tilesortspu_init.c --- cr-04-07-02/spu/tilesort/tilesortspu_init.c Sat Jun 22 00:27:19 2002 +++ cr.bak/spu/tilesort/tilesortspu_init.c Thu Jul 4 13:36:40 2002 @@ -54,6 +54,13 @@ tilesortspuGatherConfiguration( child ); tilesortspuConnectToServers(); /* set up thread0's server connection */ + if (tilesort_spu.MTU > thread0->net[0].conn->mtu) { + tilesort_spu.MTU = thread0->net[0].conn->mtu; + + /* get a buffer which can hold one big big opcode (counter computing + * against packer/pack_buffer.c) */ + tilesort_spu.buffer_size = ((((tilesort_spu.MTU - sizeof(CRMessageOpcodes) ) * 5 + 3) / 4 + 0x3) & ~0x3) + sizeof(CRMessageOpcodes); + } tilesort_spu.swap = thread0->net[0].conn->swap; tilesortspuInitThreadPacking( thread0 ); * udptcpip diff -urN cr-04-07-02/spu/tilesort/tilesortspu_net.c cr.bak/spu/tilesort/tilesortspu_net.c --- cr-04-07-02/spu/tilesort/tilesortspu_net.c Tue Apr 16 12:34:25 2002 +++ cr.bak/spu/tilesort/tilesortspu_net.c Thu Jul 4 13:36:40 2002 @@ -103,6 +103,7 @@ } if (!crStrcmp( protocol, "tcpip" ) || + !crStrcmp( protocol, "udptcpip" ) || !crStrcmp( protocol, "gm" ) ) { some_net_traffic = 1; * mtu diff -urN cr-04-07-02/spu/tilesort/tilesortspu_pinch.c cr.bak/spu/tilesort/tilesortspu_pinch.c --- cr-04-07-02/spu/tilesort/tilesortspu_pinch.c Tue Apr 2 20:45:13 2002 +++ cr.bak/spu/tilesort/tilesortspu_pinch.c Thu Jul 4 13:36:40 2002 @@ -28,7 +28,8 @@ CRASSERT(op <= thread->packer->buffer.opcode_start); \ CRASSERT(op > thread->packer->buffer.opcode_end); \ CRASSERT(data >= thread->packer->buffer.data_start); \ - CRASSERT(data < thread->packer->buffer.data_end) + CRASSERT(data < thread->packer->buffer.data_end); \ + CRASSERT(((data - op + 0x3) & ~0x3) + sizeof(CRMessageOpcodes) <= thread->packer->buffer.mtu) static const GLvectorf vdefault = {0.0f, 0.0f, 0.0f, 1.0f}; * mtu this is a problem... In fact, it shouldn't be compared to mtu : PackAlloc will recognize it is a Huge packet, and as such, it will be TCPed. diff -urN cr-04-07-02/spu/tilesort/tilesortspu_pixels.c cr.bak/spu/tilesort/tilesortspu_pixels.c --- cr-04-07-02/spu/tilesort/tilesortspu_pixels.c Thu Jun 27 20:10:08 2002 +++ cr.bak/spu/tilesort/tilesortspu_pixels.c Thu Jul 4 13:36:40 2002 @@ -40,11 +40,11 @@ return; } - if (crImageSize(format, type, width, height) > thread->net[0].conn->mtu ) { + if (crImageSize(format, type, width, height) > tilesort_spu.MTU ) { crError("DrawPixels called with insufficient MTU size\n" "Needed %d, but currently MTU is set at %d\n", crImageSize(format, type, width, height), - thread->net[0].conn->mtu ); + tilesort_spu.MTU ); return; } @@ -276,11 +276,11 @@ /* Munge the per server packing structures */ data_ptr = pack->data_current; - if (data_ptr + len > pack->data_end ) + if (!crPackCanHoldOpcode( 1, len ) ) { tilesortspuFlush( thread ); data_ptr = pack->data_current; - CRASSERT( data_ptr + len <= pack->data_end ); + CRASSERT( crPackCanHoldOpcode( 1, len ) ); } pack->data_current += len; WRITE_DATA( 0, GLint, new_x ); * udptcpip diff -urN cr-04-07-02/util/Makefile cr.bak/util/Makefile --- cr-04-07-02/util/Makefile Wed Jun 5 01:40:04 2002 +++ cr.bak/util/Makefile Thu Jul 4 13:48:03 2002 @@ -36,6 +36,7 @@ string \ threads \ tcpip \ + udptcpip \ timer \ url PRECOMP = debug_opcodes.c * mtu diff -urN cr-04-07-02/util/devnull.c cr.bak/util/devnull.c --- cr-04-07-02/util/devnull.c Fri Jun 7 18:11:02 2002 +++ cr.bak/util/devnull.c Thu Jul 4 13:36:40 2002 @@ -17,7 +17,7 @@ void *crDevnullAlloc( CRConnection *conn ) { - return crAlloc( conn->mtu ); + return crAlloc( conn->buffer_size ); } void crDevnullSingleRecv( CRConnection *conn, void *buf, unsigned int len ) * mtu diff -urN cr-04-07-02/util/filenet.c cr.bak/util/filenet.c --- cr-04-07-02/util/filenet.c Fri Jun 7 18:11:02 2002 +++ cr.bak/util/filenet.c Thu Jul 4 13:36:40 2002 @@ -109,13 +109,13 @@ if ( buf == NULL ) { crDebug( "Buffer pool was empty, so I allocated %d bytes", - (int)(sizeof(CRFileBuffer) + conn->mtu) ); + (int)(sizeof(CRFileBuffer) + conn->buffer_size) ); buf = (CRFileBuffer *) - crAlloc( sizeof(CRFileBuffer) + conn->mtu ); + crAlloc( sizeof(CRFileBuffer) + conn->buffer_size ); buf->magic = CR_FILE_BUFFER_MAGIC; buf->kind = CRFileMemory; buf->pad = 0; - buf->allocated = conn->mtu; + buf->allocated = conn->buffer_size; } #ifdef CHROMIUM_THREADSAFE @@ -221,7 +221,7 @@ CRASSERT( len > 0 ); - if ( len <= conn->mtu ) + if ( len <= conn->buffer_size ) { file_buffer = (CRFileBuffer *) crFileAlloc( conn ) - 1; } * mtu diff -urN cr-04-07-02/util/gm.c cr.bak/util/gm.c --- cr-04-07-02/util/gm.c Wed Jul 3 00:18:29 2002 +++ cr.bak/util/gm.c Thu Jul 4 13:36:40 2002 @@ -712,7 +712,7 @@ #endif if ( temp == NULL ) { - temp = (CRGmBuffer*)crAlloc( sizeof(CRGmBuffer) + gm_conn->conn->mtu ); + temp = (CRGmBuffer*)crAlloc( sizeof(CRGmBuffer) + gm_conn->conn->buffer_size ); temp->magic = CR_GM_BUFFER_RECV_MAGIC; temp->kind = CRGmMemoryUnpinned; temp->pad = 0; @@ -1016,7 +1016,7 @@ unsigned char *src; CRASSERT( buf != NULL && len > 0 ); - if ( len <= conn->mtu ) + if ( len <= conn->buffer_size ) { /* the user is doing a send from memory not allocated by the * network layer, but it does fit within a single message, so @@ -1043,11 +1043,11 @@ CRMessageMulti *msg = (CRMessageMulti *) crGmAlloc( conn ); unsigned int n_bytes; - if ( len + sizeof(*msg) > conn->mtu ) + if ( len + sizeof(*msg) > conn->buffer_size ) { msg->header.type = CR_MESSAGE_MULTI_BODY; msg->header.conn_id = conn->id; - n_bytes = conn->mtu - sizeof(*msg); + n_bytes = conn->buffer_size - sizeof(*msg); } else { * udptcpip, barf, mtu, same correction as above in client.c diff -urN cr-04-07-02/util/net.c cr.bak/util/net.c --- cr-04-07-02/util/net.c Wed Jul 3 00:18:29 2002 +++ cr.bak/util/net.c Thu Jul 4 13:36:54 2002 @@ -56,6 +56,7 @@ * networking types here. */ NETWORK_TYPE( TCPIP ); +NETWORK_TYPE( UDPTCPIP ); NETWORK_TYPE( Devnull ); NETWORK_TYPE( File ); #ifdef GM_SUPPORT @@ -106,10 +107,14 @@ conn->port = port; conn->Alloc = NULL; /* How do we allocate buffers to send? */ conn->Send = NULL; /* How do we send things? */ + conn->Barf = NULL; /* How do we barf things? */ conn->Free = NULL; /* How do we free things? */ conn->tcp_socket = 0; + conn->udp_socket = 0; + crMemset(&conn->remoteaddr, 0, sizeof(conn->remoteaddr)); conn->gm_node_id = 0; conn->mtu = mtu; + conn->buffer_size = mtu; conn->broker = broker; conn->swap = 0; conn->endianness = crDetermineEndianness(); @@ -152,6 +157,11 @@ crTCPIPInit( cr_net.recv, cr_net.close, mtu ); crTCPIPConnection( conn ); } + else if ( !crStrcmp( protocol, "udptcpip" ) ) + { + crUDPTCPIPInit( cr_net.recv, cr_net.close, mtu ); + crUDPTCPIPConnection( conn ); + } else { crError( "Unknown Protocol: \"%s\"", protocol ); @@ -211,10 +221,14 @@ conn->port = port; conn->Alloc = NULL; /* How do we allocate buffers to send? */ conn->Send = NULL; /* How do we send things? */ + conn->Barf = NULL; /* How do we barf things? */ conn->Free = NULL; /* How do we receive things? */ conn->tcp_socket = 0; + conn->udp_socket = 0; + crMemset(&conn->remoteaddr, 0, sizeof(conn->remoteaddr)); conn->gm_node_id = 0; conn->mtu = mtu; + conn->buffer_size = mtu; conn->broker = broker; conn->swap = 0; conn->endianness = crDetermineEndianness(); @@ -258,6 +272,11 @@ crTCPIPInit( cr_net.recv, cr_net.close, mtu ); crTCPIPConnection( conn ); } + else if ( !crStrcmp( protocol, "udptcpip" ) ) + { + crUDPTCPIPInit( cr_net.recv, cr_net.close, mtu ); + crUDPTCPIPConnection( conn ); + } else { crError( "Unknown Protocol: \"%s\"", protocol ); @@ -376,7 +395,7 @@ if ( bufp ) { CRASSERT( start >= *bufp ); CRASSERT( (unsigned char *) start + len <= - (unsigned char *) *bufp + conn->mtu ); + (unsigned char *) *bufp + conn->buffer_size ); } #ifndef NDEBUG @@ -394,6 +413,38 @@ conn->Send( conn, bufp, start, len ); } +/* Barf a set of commands on a connection. Pretty straightforward, just + * error checking, byte counting, and a dispatch to the protocol's + * "barf" implementation. */ + +void crNetBarf( CRConnection *conn, void **bufp, + void *start, unsigned int len ) +{ + CRMessage *msg = (CRMessage *) start; + CRASSERT( conn ); + CRASSERT( len > 0 ); + CRASSERT( conn->Barf ); + if ( bufp ) { + CRASSERT( start >= *bufp ); + CRASSERT( (unsigned char *) start + len <= + (unsigned char *) *bufp + conn->buffer_size ); + } + +#ifndef NDEBUG + if ( conn->send_credits > CR_INITIAL_RECV_CREDITS ) + { + crError( "crNetBarf: send_credits=%u, looks like there is a " + "leak (max=%u)", conn->send_credits, + CR_INITIAL_RECV_CREDITS ); + } +#endif + + conn->total_bytes_sent += len; + + msg->header.conn_id = conn->id; + conn->Barf( conn, bufp, start, len ); +} + /* Send something exact on a connection without the message length * header. */ @@ -682,6 +733,7 @@ int found_work = 0; found_work += crTCPIPRecv( ); + found_work += crUDPTCPIPRecv( ); found_work += crFileRecv( ); #ifdef GM_SUPPORT if ( cr_net.use_gm ) @@ -715,8 +767,6 @@ CRConnection *__copy_of_crMothershipConnect( void ) { char *mother_server = NULL; - int mother_port = MOTHERPORT; - char mother_url[1024]; crNetInit( NULL, NULL ); @@ -727,9 +777,7 @@ mother_server = "localhost"; } - sprintf( mother_url, "%s:%d", mother_server, mother_port ); - - return crNetConnectToServer( mother_server, 10000, 8096, 0 ); + return crNetConnectToServer( mother_server, MOTHERPORT, 8096, 0 ); } /* More code-copying lossage. I sure hope no one ever sees this code. Ever. */ * ipv6, udptcpip (not static functions so that udptcpip can reuse them) little bug about returning -1 while -ESOMETHING is expected diff -urN cr-04-07-02/util/tcpip.c cr.bak/util/tcpip.c --- cr-04-07-02/util/tcpip.c Fri Jun 7 18:11:02 2002 +++ cr.bak/util/tcpip.c Thu Jul 4 13:36:40 2002 @@ -4,6 +4,7 @@ * See the file LICENSE.txt for information on redistributing this software. */ +#define PF PF_UNSPEC #ifdef WINDOWS #define WIN32_LEAN_AND_MEAN #pragma warning( push, 3 ) @@ -180,7 +181,7 @@ CRSocket server_sock; } cr_tcpip; -static int __read_exact( CRSocket sock, void *buf, unsigned int len ) +int __read_exact( CRSocket sock, void *buf, unsigned int len ) { char *dst = (char *) buf; @@ -236,8 +237,9 @@ } } -static int __write_exact( CRSocket sock, void *buf, unsigned int len ) +int __write_exact( CRSocket sock, void *buf, unsigned int len ) { + int err; char *src = (char *) buf; while ( len > 0 ) @@ -245,13 +247,13 @@ int num_written = write( sock, src, len ); if ( num_written <= 0 ) { - if ( crTCPIPErrno( ) == EINTR ) + if ( (err = crTCPIPErrno( )) == EINTR ) { crWarning( "__write_exact(TCPIP): " "caught an EINTR, continuing" ); continue; } - return -1; + return -err; } len -= num_written; @@ -277,7 +279,7 @@ * 1) Change the size of the send/receive buffers to 64K * 2) Turn off Nagle's algorithm */ -static void __crSpankSocket( CRSocket sock ) +void __crSpankSocket( CRSocket sock ) { int sndbuf = 64*1024; int rcvbuf = sndbuf; @@ -325,11 +327,9 @@ void crTCPIPAccept( CRConnection *conn, unsigned short port ) { int err; - struct sockaddr_in servaddr; - struct sockaddr addr; - socklen_t addr_length; - struct hostent *host; - struct in_addr sin_addr; + struct sockaddr_storage addr; + socklen_t addr_length; + char host[NI_MAXHOST]; static unsigned short last_port = 0; @@ -338,31 +338,54 @@ /* with the new OOB stuff, we can have multiple ports being * accepted on, so we need to redo the server socket every time. */ + char port_s[NI_MAXSERV]; + struct addrinfo *res,*cur; + struct addrinfo hints; - cr_tcpip.server_sock = socket( AF_INET, SOCK_STREAM, 0 ); - if ( cr_tcpip.server_sock == -1 ) - { - err = crTCPIPErrno( ); - crError( "Couldn't create socket: %s", crTCPIPErrorString( err ) ); - } - __crSpankSocket( cr_tcpip.server_sock ); + sprintf(port_s, "%u", (short unsigned) port); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = INADDR_ANY; - servaddr.sin_port = htons( port ); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF; + hints.ai_socktype = SOCK_STREAM; - if ( bind( cr_tcpip.server_sock, (struct sockaddr *) &servaddr, sizeof(servaddr) ) ) - { - err = crTCPIPErrno( ); - crError( "Couldn't bind to socket (port=%d): %s", port, crTCPIPErrorString( err ) ); - } - last_port = port; + err = getaddrinfo( NULL, port_s, &hints, &res ); + if ( err ) + crError( "Couldn't find local TCP port %s: %s", port_s, gai_strerror(err) ); - if ( listen( cr_tcpip.server_sock, 100 /* max pending connections */ ) ) + for (cur=res;cur;cur=cur->ai_next) { - err = crTCPIPErrno( ); - crError( "Couldn't listen on socket: %s", crTCPIPErrorString( err ) ); + cr_tcpip.server_sock = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + if ( cr_tcpip.server_sock == -1 ) + { + err = crTCPIPErrno( ); + if (err != EAFNOSUPPORT) + crWarning( "Couldn't create socket of family %i: %s, trying another", cur->ai_family, crTCPIPErrorString( err ) ); + continue; + } + __crSpankSocket( cr_tcpip.server_sock ); + + if ( bind( cr_tcpip.server_sock, cur->ai_addr, cur->ai_addrlen ) ) + { + err = crTCPIPErrno( ); + crWarning( "Couldn't bind to socket (port=%d): %s", port, crTCPIPErrorString( err ) ); + crCloseSocket( cr_tcpip.server_sock ); + continue; + } + last_port = port; + + if ( listen( cr_tcpip.server_sock, 100 /* max pending connections */ ) ) + { + err = crTCPIPErrno( ); + crWarning( "Couldn't listen on socket: %s", crTCPIPErrorString( err ) ); + crCloseSocket( cr_tcpip.server_sock ); + continue; + } + break; } + freeaddrinfo(res); + if (!cur) + crError( "Couldn't find local TCP port %s", port_s); } if (conn->broker) @@ -395,17 +418,24 @@ err = crTCPIPErrno( ); crError( "Couldn't accept client: %s", crTCPIPErrorString( err ) ); } - sin_addr = ((struct sockaddr_in *) &addr)->sin_addr; - host = gethostbyaddr( (char *) &sin_addr, sizeof( sin_addr), AF_INET ); - if (host == NULL ) - { - char *temp = inet_ntoa( sin_addr ); - conn->hostname = crStrdup( temp ); + + err = getnameinfo ( (struct sockaddr *) &addr, addr_length, + host, sizeof( host), + NULL, 0, NI_NAMEREQD); + if ( err ) + { + err = getnameinfo ( (struct sockaddr *) &addr, addr_length, + host, sizeof( host), + NULL, 0, NI_NUMERICHOST); + if ( err ) + conn->hostname = "unknown !"; + else + conn->hostname = crStrdup( host ); } else { char *temp; - conn->hostname = crStrdup( host->h_name ); + conn->hostname = crStrdup( host ); temp = conn->hostname; while (*temp && *temp != '.' ) @@ -429,13 +459,13 @@ if ( buf == NULL ) { crDebug( "Buffer pool was empty, so I allocated %d bytes", - (unsigned int)sizeof(CRTCPIPBuffer) + conn->mtu ); + (unsigned int)sizeof(CRTCPIPBuffer) + conn->buffer_size ); buf = (CRTCPIPBuffer *) - crAlloc( sizeof(CRTCPIPBuffer) + conn->mtu ); + crAlloc( sizeof(CRTCPIPBuffer) + conn->buffer_size ); buf->magic = CR_TCPIP_BUFFER_MAGIC; buf->kind = CRTCPIPMemory; buf->pad = 0; - buf->allocated = conn->mtu; + buf->allocated = conn->buffer_size; } #ifdef CHROMIUM_THREADSAFE @@ -458,14 +488,11 @@ if ( bufp == NULL ) { + unsigned int len_swap = conn->swap ? SWAP32(len) : len; /* we are doing synchronous sends from user memory, so no need * to get fancy. Simply write the length & the payload and * return. */ - if (conn->swap) - { - len = SWAP32(len); - } - crTCPIPWriteExact( conn, &len, sizeof(len) ); + crTCPIPWriteExact( conn, &len_swap, sizeof(len_swap) ); crTCPIPWriteExact( conn, start, len ); return; } @@ -506,7 +533,7 @@ *bufp = NULL; } -static void __dead_connection( CRConnection *conn ) +void __dead_connection( CRConnection *conn ) { crWarning( "Dead connection (sock=%d, host=%s)", conn->tcp_socket, conn->hostname ); @@ -517,7 +544,7 @@ exit( 0 ); } -static int __crSelect( int n, fd_set *readfds, struct timeval *timeout ) +int __crSelect( int n, fd_set *readfds, struct timeval *timeout ) { for ( ; ; ) { @@ -600,7 +627,7 @@ * (MSG_PEEK flag to recv()?) if the connection isn't * enabled. */ - struct sockaddr s; + struct sockaddr_storage s; socklen_t slen; fd_set only_fd; /* testing single fd */ CRSocket sock = conn->tcp_socket; @@ -632,7 +659,7 @@ FD_SET( sock, &only_fd ); slen = sizeof( s ); /* Check that the socket is REALLY connected */ - if (getpeername(sock, &s, &slen) < 0) { + if (getpeername(sock, (struct sockaddr *) &s, &slen) < 0) { FD_CLR(sock, &read_fds); msock = sock; } @@ -704,7 +731,7 @@ CRASSERT( len > 0 ); - if ( len <= conn->mtu ) + if ( len <= conn->buffer_size ) { tcpip_buffer = (CRTCPIPBuffer *) crTCPIPAlloc( conn ) - 1; } @@ -827,36 +854,24 @@ int crTCPIPDoConnect( CRConnection *conn ) { - struct sockaddr_in servaddr; - struct hostent *hp; + char port_s[NI_MAXSERV]; + struct addrinfo *res,*cur; + struct addrinfo hints; int err; - conn->tcp_socket = socket( AF_INET, SOCK_STREAM, 0 ); - if ( conn->tcp_socket < 0 ) - { - int err = crTCPIPErrno( ); - crWarning( "socket error: %s", crTCPIPErrorString( err ) ); - return 0; - } + sprintf(port_s, "%u", (short unsigned) conn->port); - /* Set up the socket the way *we* want. */ - __crSpankSocket( conn->tcp_socket ); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF; + hints.ai_socktype = SOCK_STREAM; - /* Standard Berkeley sockets mumbo jumbo */ - hp = gethostbyname( conn->hostname ); - if ( !hp ) + err = getaddrinfo( conn->hostname, port_s, &hints, &res); + if ( err ) { - crWarning( "Unknown host: \"%s\"", conn->hostname ); + crWarning( "Unknown host: \"%s\": %s", conn->hostname, gai_strerror(err) ); return 0; } - memset( &servaddr, 0, sizeof(servaddr) ); - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons( (short) conn->port ); - - memcpy( (char *) &servaddr.sin_addr, hp->h_addr, - sizeof(servaddr.sin_addr) ); - if (conn->broker) { CRConnection *mother; @@ -866,10 +881,11 @@ if (!__copy_of_crMothershipSendString( mother, response, "connectrequest tcpip %s %d %d", conn->hostname, conn->port, conn->endianness) ) { + freeaddrinfo(res); crError( "Mothership didn't like my connect request request" ); } - __copy_of_crMothershipDisconnect( mother ); + __copy_of_crMothershipDisconnect( mother ); sscanf( response, "%d %d", &(conn->id), &(remote_endianness) ); @@ -878,34 +894,46 @@ conn->swap = 1; } } - for (;;) + for (cur=res;cur;) { - if ( !connect( conn->tcp_socket, (struct sockaddr *) &servaddr, - sizeof(servaddr) ) ) - break; + conn->tcp_socket = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + if ( conn->tcp_socket < 0 ) + { + int err = crTCPIPErrno( ); + if (err != EAFNOSUPPORT) + crWarning( "socket error: %s, trying another way", crTCPIPErrorString( err ) ); + cur=cur->ai_next; + continue; + } + + /* Set up the socket the way *we* want. */ + __crSpankSocket( conn->tcp_socket ); + + if ( !connect( conn->tcp_socket, cur->ai_addr, cur->ai_addrlen ) ) { + freeaddrinfo(res); + return 1; + } + crCloseSocket( conn->tcp_socket ); err = crTCPIPErrno( ); if ( err == EADDRINUSE || err == ECONNREFUSED ) - { - /* Here's where we might try again on another - * port -- don't think we'll do that any more. */ crWarning( "Couldn't connect to %s:%d, %s", conn->hostname, conn->port, crTCPIPErrorString( err ) ); - return 0; - } + else if ( err == EINTR ) { crWarning( "connection to %s:%d " "interruped, trying again", conn->hostname, conn->port ); + continue; } else - { crWarning( "Couldn't connect to %s:%d, %s", conn->hostname, conn->port, crTCPIPErrorString( err ) ); - return 0; - } + cur=cur->ai_next; } - return 1; + freeaddrinfo(res); + crWarning( "Couln't find any suitable way to connect to %s", conn->hostname ); + return 0; } void crTCPIPDoDisconnect( CRConnection *conn ) * udptcpip Can't reuse much of tcpip.c's functions, since they use TCPIP's pool of buffer If the CRUDPTCPIPBuffer structure eventually doesn't grow, we might use CRTCPIPBuffer instead, hence sharing buffers (good idea IMHO, since we then may share functions) diff -urN cr-04-07-02/util/udptcpip.c cr.bak/util/udptcpip.c --- cr-04-07-02/util/udptcpip.c Thu Jan 1 01:00:00 1970 +++ cr.bak/util/udptcpip.c Thu Jul 4 13:46:44 2002 @@ -0,0 +1,1065 @@ +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#define PF PF_UNSPEC +#ifdef WINDOWS +#define WIN32_LEAN_AND_MEAN +#pragma warning( push, 3 ) +#include +#pragma warning( pop ) +#pragma warning( disable : 4514 ) +#pragma warning( disable : 4127 ) +typedef int ssize_t; +#define write(a,b,c) send(a,b,c,0) +#else +#include +#ifdef DARWIN +typedef unsigned int socklen_t; +#endif +#include +#include +#include +#ifdef LINUX +#define IP_MTU 14 +#endif +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#ifdef AIX +#include +#endif + +#include "cr_error.h" +#include "cr_mem.h" +#include "cr_string.h" +#include "cr_bufpool.h" +#include "cr_net.h" +#include "cr_endian.h" +#include "cr_threads.h" +#include "net_internals.h" + +#ifdef WINDOWS +#define EADDRINUSE WSAEADDRINUSE +#define ECONNREFUSED WSAECONNREFUSED +#endif + +typedef enum { + CRUDPTCPIPMemory, + CRUDPTCPIPMemoryBig +} CRUDPTCPIPBufferKind; + +#define CR_UDPTCPIP_BUFFER_MAGIC 0x89134532 + +typedef struct CRUDPTCPIPBuffer { + unsigned int magic; + CRUDPTCPIPBufferKind kind; + unsigned int len; + unsigned int allocated; + unsigned int pad; +} CRUDPTCPIPBuffer; + + +/* Forward decl */ +static void crUDPTCPIPFree( CRConnection *conn, void *buf ); + +#ifdef WINDOWS + +#undef ECONNRESET +#define ECONNRESET WSAECONNRESET +#undef EINTR +#define EINTR WSAEINTR + +#endif +extern int crTCPIPErrno( void ); +extern char *crTCPIPErrorString( int err ); + +extern void crCloseSocket( CRSocket sock ); + +extern int crSameAddr(struct sockaddr *addr1, struct sockaddr *addr2); + +static struct { + int initialized; + int num_conns; + CRConnection **conns; + CRBufferPool bufpool; +#ifdef CHROMIUM_THREADSAFE + CRmutex mutex; + CRmutex recvmutex; +#endif + CRNetReceiveFunc recv; + CRNetCloseFunc close; + CRSocket server_sock; +} cr_udptcpip; + +extern int __read_exact( CRSocket sock, void *buf, unsigned int len ); +extern void crTCPIPReadExact( CRSocket sock, void *buf, unsigned int len ); +extern int __write_exact( CRSocket sock, void *buf, unsigned int len ); +extern void crTCPIPSend( CRConnection *conn, void **bufp, void *start, unsigned int len ); +extern void crTCPIPWriteExact( CRConnection *conn, void *buf, unsigned int len ); +extern void __crSpankSocket( CRSocket sock ); + +#if defined( WINDOWS ) || defined( IRIX ) || defined( IRIX64 ) +typedef int socklen_t; +#endif + +void crUDPIPWriteExact( CRConnection *conn, void *buf, unsigned int len ) +{ + int retval; + if ( len > conn->mtu + sizeof(conn->seq) ) + { + crWarning( "crUDPIPWriteExact(%d): too big a packet for mtu %d, dropping !", len, conn->mtu + sizeof(conn->seq) ); + return; + } + retval = sendto( conn->udp_socket, buf, len, 0, + (struct sockaddr *) &(conn->remoteaddr), sizeof(conn->remoteaddr)); + if ( retval <= 0 ) + { + int err = crTCPIPErrno( ); + //crError( "crUDPIPWriteExact(%d): %s", len, crTCPIPErrorString( err ) ); + crWarning( "crUDPIPWriteExact(%d): %s", len, crTCPIPErrorString( err ) ); +#ifdef LINUX + if ( err == EMSGSIZE ) + { + int opt; + socklen_t leno = sizeof(opt); + crDebug( "Too big a UDP packet(%d), looking at new MTU...", len ); + if ( getsockopt( conn->udp_socket, SOL_IP, IP_MTU_DISCOVER, &opt, &leno) == -1) + { + err = crTCPIPErrno( ); + crWarning( "Couldn't determine whether PMTU discovery is used : %s", crTCPIPErrorString( err ) ); + return; + } + if ( leno != sizeof(opt) ) + { + crWarning( "Unexpected length %d for PMTU_DISCOVERY option length", leno ); + return; + } + if ( opt == IP_PMTUDISC_DONT ) + { + crWarning( "Uh, PMTU discovery isn't enabled ?!" ); + return; + } + if ( getsockopt( conn->udp_socket, SOL_IP, IP_MTU, &opt, &leno) == -1 ) + { + err = crTCPIPErrno( ); + crWarning( "Couldn't determine the MTU : %s", crTCPIPErrorString( err ) ); + return; + } + if ( leno != sizeof(opt) ) + { + crWarning( "Unexpected length %d for MTU option length", leno ); + return; + } + opt -= sizeof(conn->seq) + sizeof(struct udphdr) + sizeof(struct ip6_hdr); + if (opt >= conn->mtu) + { + crWarning( "But MTU discovery is still bigger ! Narrowing it by hand to %d", conn->mtu = (conn->mtu * 2 / 3) & ~0x3 ); + } + else + { + crDebug( "new MTU is %d", opt ); + conn->mtu = opt & ~0x3; + } + } +#endif + } +} + +static void crUDPTCPIPAccept( CRConnection *conn, unsigned short port ) +{ + int err; + struct sockaddr_storage addr; + socklen_t addr_length; + char host[NI_MAXHOST]; + struct addrinfo *res,*cur; + struct addrinfo hints; + + static unsigned short last_port = 0; + + if (port != last_port) + { + /* with the new OOB stuff, we can have multiple ports being + * accepted on, so we need to redo the server socket every time. + */ + char port_s[NI_MAXSERV]; + + sprintf(port_s, "%u", (short unsigned) port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF; + hints.ai_socktype = SOCK_STREAM; + + err = getaddrinfo( NULL, port_s, &hints, &res); + if ( err ) + crError( "Couldn't find local TCP port %s: %s", port_s, gai_strerror(err)); + + for (cur=res;cur;cur=cur->ai_next) + { + cr_udptcpip.server_sock = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + if ( cr_udptcpip.server_sock == -1 ) + { + err = crTCPIPErrno( ); + if (err != EAFNOSUPPORT) + crWarning( "Couldn't create socket of family %i: %s, trying another", cur->ai_family, crTCPIPErrorString( err ) ); + continue; + } + __crSpankSocket( cr_udptcpip.server_sock ); + + if ( bind( cr_udptcpip.server_sock, cur->ai_addr, cur->ai_addrlen ) ) + { + err = crTCPIPErrno( ); + crWarning( "Couldn't bind to socket (port=%d): %s", port, crTCPIPErrorString( err ) ); + crCloseSocket( cr_udptcpip.server_sock ); + continue; + } + last_port = port; + + if ( listen( cr_udptcpip.server_sock, 100 /* max pending connections */ ) ) + { + err = crTCPIPErrno( ); + crWarning( "Couldn't listen on socket: %s", crTCPIPErrorString( err ) ); + crCloseSocket( cr_udptcpip.server_sock ); + continue; + } + break; + } + freeaddrinfo(res); + if (!cur) + crError( "Couldn't find local TCP port %s", port_s); + } + + if (conn->broker) + { + CRConnection *mother; + char response[8096]; + char my_hostname[256]; + + mother = __copy_of_crMothershipConnect( ); + + if ( crGetHostname( my_hostname, sizeof( my_hostname ) ) ) + { + crError( "Couldn't determine my own hostname in crUDPTCPIPAccept!" ); + } + + if (!__copy_of_crMothershipSendString( mother, response, "acceptrequest udptcpip %s %d %d", my_hostname, conn->port, conn->endianness ) ) + { + crError( "Mothership didn't like my accept request request" ); + } + + __copy_of_crMothershipDisconnect( mother ); + + sscanf( response, "%d", &(conn->id) ); + } + + addr_length = sizeof( addr ); + conn->tcp_socket = accept( cr_udptcpip.server_sock, (struct sockaddr *) &addr, &addr_length ); + if (conn->tcp_socket == -1) + { + err = crTCPIPErrno( ); + crError( "Couldn't accept client: %s", crTCPIPErrorString( err ) ); + } + + err = getnameinfo ( (struct sockaddr *) &addr, addr_length, + host, sizeof( host), + NULL, 0, NI_NAMEREQD); + if ( err ) + { + err = getnameinfo ( (struct sockaddr *) &addr, addr_length, + host, sizeof( host), + NULL, 0, NI_NUMERICHOST); + if ( err ) + conn->hostname = "unknown !"; + else + conn->hostname = crStrdup( host ); + } + else + { + char *temp; + conn->hostname = crStrdup( host ); + + temp = conn->hostname; + while (*temp && *temp != '.' ) + temp++; + *temp = '\0'; + } + + crDebug( "Accepted connection from \"%s\".", conn->hostname ); + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF; + hints.ai_socktype = SOCK_DGRAM; + + err = getaddrinfo( NULL, "0", &hints, &res); + if ( err ) + crError( "Couldn't find local UDP port: %s", gai_strerror(err)); + + conn->udp_socket = -1; + + for (cur=res;cur;cur=cur->ai_next) + { + conn->udp_socket = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + if ( conn->udp_socket == -1 ) + { + err = crTCPIPErrno( ); + if (err != EAFNOSUPPORT) + crWarning( "Couldn't create socket of family %i: %s, trying another one", cur->ai_family, crTCPIPErrorString( err ) ); + continue; + } + if ( bind( conn->udp_socket, cur->ai_addr, cur->ai_addrlen ) ) + { + err = crTCPIPErrno( ); + crWarning( "Couldn't bind socket: %s", crTCPIPErrorString( err ) ); + crCloseSocket( conn->udp_socket ); + conn->udp_socket = -1; + continue; + } + break; + + } + + freeaddrinfo(res); + + if ( conn->udp_socket < 0 ) + crError( "Couldn't find local UDP port" ); + + addr_length = sizeof(addr); + err = getsockname( conn->udp_socket, (struct sockaddr *) &addr, &addr_length ); + + if ( err == -1 ) + crError( "Couldn't get our local UDP port: %s", crTCPIPErrorString( err ) ); + + switch (((struct sockaddr *) &addr)->sa_family) { + case AF_INET: + crTCPIPWriteExact( conn, &((struct sockaddr_in *)&addr)->sin_port, + sizeof(((struct sockaddr_in *)&addr)->sin_port)); + break; + case AF_INET6: + crTCPIPWriteExact( conn, &((struct sockaddr_in6 *)&addr)->sin6_port, + sizeof(((struct sockaddr_in6 *)&addr)->sin6_port)); + break; + default: + crError( "Unknown address family: %d", ((struct sockaddr *) &addr)->sa_family); + } +} + +void *crUDPTCPIPAlloc( CRConnection *conn ) +{ + CRUDPTCPIPBuffer *buf; + +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&cr_udptcpip.mutex); +#endif + + buf = (CRUDPTCPIPBuffer *) crBufferPoolPop( &cr_udptcpip.bufpool ); + + if ( buf == NULL ) + { + crDebug( "Buffer pool was empty, so I allocated %d bytes", + (unsigned int)sizeof(CRUDPTCPIPBuffer) + conn->buffer_size ); + buf = (CRUDPTCPIPBuffer *) + crAlloc( sizeof(CRUDPTCPIPBuffer) + conn->buffer_size ); + buf->magic = CR_UDPTCPIP_BUFFER_MAGIC; + buf->kind = CRUDPTCPIPMemory; + buf->pad = 0; + buf->allocated = conn->buffer_size; + } + +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&cr_udptcpip.mutex); +#endif + + return (void *)( buf + 1 ); +} + +static unsigned long long safelen=0; +static void crUDPTCPIPSend( CRConnection *conn, void **bufp, + void *start, unsigned int len ) +{ + static unsigned long long safeblip=0; + CRUDPTCPIPBuffer *udptcpip_buffer; + unsigned int *lenp; + + safelen+=len; + if (safelen-safeblip>100000) + { + safeblip=safelen; + crDebug( "%lldKo safe", safelen/(1LL<<10) ); + } + + conn->seq++; + //crDebug("sendseq++ -> %u", conn->seq); + if (len <= conn->mtu) + { + //unsigned char *c; + if (len>1000) { + crDebug("writing safely %d bytes",len); + /*for (c=start;len;c++,len--) + fprintf(stderr,"%3d ",*c); + fprintf(stderr,"\n");*/ + } + } else { + crDebug("writing big packet %d", len); + } + + if ( bufp == NULL ) + { + unsigned int len_swap = conn->swap ? SWAP32(len) : len; + /* we are doing synchronous sends from user memory, so no need + * to get fancy. Simply write the length & the payload and + * return. */ + crTCPIPWriteExact( conn, &len_swap, sizeof(len_swap) ); + crTCPIPWriteExact( conn, start, len ); + return; + } + + udptcpip_buffer = (CRUDPTCPIPBuffer *)(*bufp) - 1; + + CRASSERT( udptcpip_buffer->magic == CR_UDPTCPIP_BUFFER_MAGIC ); + + /* All of the buffers passed to the send function were allocated + * with crTCPIPAlloc(), which includes a header with a 4 byte + * length field, to insure that we always have a place to write + * the length field, even when start == *bufp. */ + lenp = (unsigned int *) start - 1; + if (conn->swap) + { + *lenp = SWAP32(len); + } + else + { + *lenp = len; + } + + if ( __write_exact( conn->tcp_socket, lenp, len + sizeof(*lenp) ) < 0 ) + { + int err = crTCPIPErrno( ); + crError( "crUDPTCPIPSend: %s", crTCPIPErrorString( err ) ); + } + + /* reclaim this pointer for reuse and try to keep the client from + accidentally reusing it directly */ +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&cr_udptcpip.mutex); +#endif + crBufferPoolPush( &cr_udptcpip.bufpool, udptcpip_buffer ); +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&cr_udptcpip.mutex); +#endif + *bufp = NULL; +} + +static unsigned long long barflen=0; +static void crUDPTCPIPBarf( CRConnection *conn, void **bufp, + void *start, unsigned int len) +{ + static unsigned long long barfblip=0; + static const unsigned int sizes[]={ + 0,10,50,100,500,1000,5000,10000,UINT_MAX + }; + static unsigned long long nbs[sizeof(sizes)/sizeof(int)] = { [sizeof(sizes)/sizeof(int)-1] 0 }; + static unsigned long long nb; + unsigned int *seqp; + CRUDPTCPIPBuffer *udptcpip_buffer; + int i; + + if (!bufp) { + crDebug("writing safely %d bytes because from user memory",len); + return crUDPTCPIPSend( conn, bufp, start, len); + } + if (len > conn->mtu) { + crDebug("writing safely %d bytes because that is too much for MTU %d", len, conn->mtu); + return crUDPTCPIPSend( conn, bufp, start, len); + } + + barflen+=len; + nb++; + for(i=0;;i++) + if (len > sizes[i] && len <= sizes[(i+1)]) { + nbs[i]++; + break; + } + if (barflen-barfblip>1<<22) { + barfblip=barflen; + crDebug( "send traffic: %lld%sMo barfed %lldKo safe", barflen/(1LL<<20), barflen?"":".0", safelen/(1LL<<10) ); + if (nb) { + for (i=0;imagic == CR_UDPTCPIP_BUFFER_MAGIC ); + + seqp = (unsigned int *) start - 1; + if (conn->swap) + { + *seqp = SWAP32(conn->seq); + } + else + { + *seqp = conn->seq; + } + //if (random()%2) + crUDPIPWriteExact( conn, seqp, len + sizeof(*seqp) ); + /*else { + unsigned char *c; + crDebug("dropped packet of length %d", len); + for (c=start;len;c++,len--) + fprintf(stderr,"%3d ",*c); + fprintf(stderr,"\n"); + }*/ + //crDebug("sendseq : %u", conn->seq); + + /* reclaim this pointer for reuse and try to keep the client from + accidentally reusing it directly */ +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&cr_udptcpip.mutex); +#endif + crBufferPoolPush( &cr_udptcpip.bufpool, udptcpip_buffer ); +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&cr_udptcpip.mutex); +#endif + *bufp = NULL; +} + +extern void __dead_connection( CRConnection *conn ); +extern int __crSelect( int n, fd_set *readfds, struct timeval *timeout ); + +static void crUDPTCPIPFree( CRConnection *conn, void *buf ) +{ + CRUDPTCPIPBuffer *udptcpip_buffer = (CRUDPTCPIPBuffer *) buf - 1; + + CRASSERT( udptcpip_buffer->magic == CR_UDPTCPIP_BUFFER_MAGIC ); + conn->recv_credits += udptcpip_buffer->len; + + switch ( udptcpip_buffer->kind ) + { + case CRUDPTCPIPMemory: +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&cr_udptcpip.mutex); +#endif + crBufferPoolPush( &cr_udptcpip.bufpool, udptcpip_buffer ); +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&cr_udptcpip.mutex); +#endif + break; + + case CRUDPTCPIPMemoryBig: + crFree( udptcpip_buffer ); + break; + + default: + crError( "Weird buffer kind trying to free in crUDPTCPIPFree: %d", udptcpip_buffer->kind ); + } +} + +static void crUDPTCPIPReceive( CRConnection *conn, CRUDPTCPIPBuffer *buf, int len ) +{ + CRMessage *msg; + CRMessageType cached_type; +#if 0 + crLogRead( len ); +#endif + + conn->recv_credits -= len; + + conn->total_bytes_recv += len; + + msg = (CRMessage *) (buf + 1); + cached_type = msg->header.type; + if (conn->swap) + { + msg->header.type = (CRMessageType) SWAP32( msg->header.type ); + msg->header.conn_id = (CRMessageType) SWAP32( msg->header.conn_id ); + } + if (!cr_udptcpip.recv( conn, buf + 1, len )) + { + crNetDefaultRecv( conn, buf + 1, len ); + } + + /* CR_MESSAGE_OPCODES is freed in + * crserver/server_stream.c + * + * OOB messages are the programmer's problem. -- Humper 12/17/01 */ + if (cached_type != CR_MESSAGE_OPCODES && cached_type != CR_MESSAGE_OOB) + { + crUDPTCPIPFree( conn, buf + 1 ); + } +} + +int crUDPTCPIPRecv( void ) +{ + int num_ready, max_fd; + fd_set read_fds; + int i; + //int msock = -1; /* assumed mothership socket */ + /* ensure we don't get caught with a new thread connecting */ + int num_conns = cr_udptcpip.num_conns; + +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&cr_udptcpip.recvmutex); +#endif + + max_fd = 0; + FD_ZERO( &read_fds ); + for ( i = 0; i < num_conns; i++ ) + { + CRConnection *conn = cr_udptcpip.conns[i]; + if (!conn) continue; + if ( conn->recv_credits > 0 || conn->type != CR_UDPTCPIP ) + { + /* + * NOTE: may want to always put the FD in the descriptor + * set so we'll notice broken connections. Down in the + * loop that iterates over the ready sockets only peek + * (MSG_PEEK flag to recv()?) if the connection isn't + * enabled. + */ + CRSocket sock = conn->tcp_socket; + + if ( (int) sock + 1 > max_fd ) + max_fd = (int) sock + 1; + FD_SET( sock, &read_fds ); + + sock = conn->udp_socket; + if ( (int) sock + 1 > max_fd ) + max_fd = (int) sock + 1; + FD_SET( sock, &read_fds ); + } + } + + if (!max_fd) { +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&cr_udptcpip.recvmutex); +#endif + return 0; + } + + if ( num_conns ) + { + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 500; + num_ready = __crSelect( max_fd, &read_fds, &timeout ); + } + else + { + crWarning( "Waiting for first connection..." ); + num_ready = __crSelect( max_fd, &read_fds, NULL ); + } + + if ( num_ready == 0 ) { +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&cr_udptcpip.recvmutex); +#endif + return 0; + } + + for ( i = 0; i < num_conns; i++ ) + { + CRConnection *conn = cr_udptcpip.conns[i]; + CRUDPTCPIPBuffer *buf; + int read_ret; + int len; + int sock; + + if (!conn) continue; + + if ( conn->udp_packet ) { + unsigned int *seq; + buf = conn->udp_packet; + seq = (unsigned int *)(buf + 1) - 1; + if ( *seq == conn->seq ) + { + //crDebug( "seq == conn->seq == %u, ok, can go on", *seq ); + crUDPTCPIPReceive( conn, buf, + conn->udp_packetlen ); + conn->udp_packet = NULL; + i--; // can now read other packets + continue; + } + if ( *seq - conn->seq > (~(0U)) >> 1 ) + { + crWarning( "%u is older than %u, dropping", *seq, conn->seq ); + crUDPTCPIPFree( conn, buf ); + continue; + } + } + else if ( FD_ISSET(conn->udp_socket, &read_fds ) ) + { + CRUDPTCPIPBuffer *buf = ((CRUDPTCPIPBuffer *) crUDPTCPIPAlloc( conn )) - 1; + unsigned int *seq = ((unsigned int *) (buf + 1)) - 1; + int len; + FD_CLR( conn->udp_socket, &read_fds ); + + len = recv( conn->udp_socket, seq, + buf->allocated + sizeof(*seq), MSG_TRUNC ); + + CRASSERT( len > 0 ); + CRASSERT( len <= buf->allocated + sizeof(*seq) ); + if ( len < sizeof(*seq) ) + { + crWarning( "too short a UDP packet : %d", len); + crUDPTCPIPFree( conn, buf ); + continue; + } + + buf->len = len; + + if ( *seq == conn->seq) + { + //crDebug( "seq == conn->seq == %u, ok, can go on", *seq ); + crUDPTCPIPReceive( conn, buf, len ); + continue; + } + + if ( *seq - conn->seq > (~(0U)) >> 1 ) + { + crWarning( "%u is older than %u, dropping", *seq, conn->seq ); + crUDPTCPIPFree( conn, buf ); + continue; + } + //crDebug( "oh, so seq increased (now %d, should become %d), let's see that", conn->seq, *seq ); + conn->udp_packet = buf; + conn->udp_packetlen = len; + } + + sock = conn->tcp_socket; + if ( !FD_ISSET( sock, &read_fds ) ) + continue; + + read_ret = __read_exact( sock, &len, sizeof(len) ); + if ( read_ret <= 0 ) + { + __dead_connection( conn ); + i--; + continue; + } + + if (conn->swap) + { + len = SWAP32(len); + } + + CRASSERT( len > 0 ); + + if ( len <= conn->buffer_size ) + { + buf = (CRUDPTCPIPBuffer *) crUDPTCPIPAlloc( conn ) - 1; + } + else + { + buf = (CRUDPTCPIPBuffer *) + crAlloc( sizeof(*buf) + len ); + buf->magic = CR_UDPTCPIP_BUFFER_MAGIC; + buf->kind = CRUDPTCPIPMemoryBig; + buf->pad = 0; + } + + buf->len = len; + + read_ret = __read_exact( sock, buf + 1, len ); + if ( read_ret <= 0 ) + { + crWarning( "Bad juju: %d %d", buf->allocated, len ); + crFree( buf ); + __dead_connection( conn ); + i--; + continue; + } + + crUDPTCPIPReceive( conn, buf, len ); + // and increment sequence number + conn->seq++; + //crDebug( "seq is now %u", conn->seq ); + } + +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&cr_udptcpip.recvmutex); +#endif + + return 1; +} + +static void crUDPTCPIPHandleNewMessage( CRConnection *conn, CRMessage *msg, + unsigned int len ) +{ + CRUDPTCPIPBuffer *buf = ((CRUDPTCPIPBuffer *) msg) - 1; + + /* build a header so we can delete the message later */ + buf->magic = CR_UDPTCPIP_BUFFER_MAGIC; + buf->kind = CRUDPTCPIPMemory; + buf->len = len; + buf->pad = 0; + + if (!cr_udptcpip.recv( conn, msg, len )) + { + crNetDefaultRecv( conn, msg, len ); + } +} + +static void crUDPTCPIPInstantReclaim( CRConnection *conn, CRMessage *mess ) +{ + crUDPTCPIPFree( conn, mess ); +} + +void crUDPTCPIPInit( CRNetReceiveFunc recvFunc, CRNetCloseFunc closeFunc, unsigned int mtu ) +{ + (void) mtu; + if ( cr_udptcpip.initialized ) + { + if ( cr_udptcpip.recv == NULL && cr_udptcpip.close == NULL ) + { + cr_udptcpip.recv = recvFunc; + cr_udptcpip.close = closeFunc; + } + else + { + CRASSERT( cr_udptcpip.recv == recvFunc ); + CRASSERT( cr_udptcpip.close == closeFunc ); + } + return; + } + + cr_udptcpip.num_conns = 0; + cr_udptcpip.conns = NULL; + + cr_udptcpip.server_sock = -1; + +#ifdef CHROMIUM_THREADSAFE + crInitMutex(&cr_udptcpip.mutex); + crInitMutex(&cr_udptcpip.recvmutex); +#endif + crBufferPoolInit( &cr_udptcpip.bufpool, 16 ); + + cr_udptcpip.recv = recvFunc; + cr_udptcpip.close = closeFunc; + + cr_udptcpip.initialized = 1; +} +/* The function that actually connects. This should only be called by clients + * Servers have another way to set up the socket. */ + +static int crUDPTCPIPDoConnect( CRConnection *conn ) +{ + char port_s[NI_MAXSERV]; + in_port_t port; + struct addrinfo *res,*cur; + struct addrinfo hints; + int err; + + // first connect to its tcp port + sprintf(port_s, "%u", (short unsigned) conn->port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF; + hints.ai_socktype = SOCK_STREAM; + + err = getaddrinfo( conn->hostname, port_s, &hints, &res); + if ( err ) + { + crWarning( "Unknown host: \"%s\": %s", conn->hostname, gai_strerror(err) ); + return 0; + } + + if (conn->broker) + { + CRConnection *mother; + char response[8096]; + int remote_endianness; + mother = __copy_of_crMothershipConnect( ); + + if (!__copy_of_crMothershipSendString( mother, response, "connectrequest udptcpip %s %d %d", conn->hostname, conn->port, conn->endianness) ) + { + freeaddrinfo(res); + crError( "Mothership didn't like my connect request request" ); + } + + __copy_of_crMothershipDisconnect( mother ); + + sscanf( response, "%d %d", &(conn->id), &(remote_endianness) ); + + if (conn->endianness != remote_endianness) + { + conn->swap = 1; + } + } + for (cur=res;cur;) + { + conn->tcp_socket = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + if ( conn->tcp_socket < 0 ) + { + int err = crTCPIPErrno( ); + if (err != EAFNOSUPPORT) + crWarning( "socket error: %s, trying another way", crTCPIPErrorString( err ) ); + cur=cur->ai_next; + continue; + } + + /* Set up the socket the way *we* want. */ + __crSpankSocket( conn->tcp_socket ); + + if ( !connect( conn->tcp_socket, cur->ai_addr, cur->ai_addrlen ) ) + break; + + crCloseSocket( conn->tcp_socket ); + + err = crTCPIPErrno( ); + if ( err == EADDRINUSE || err == ECONNREFUSED ) + crWarning( "Couldn't connect to %s:%d, %s", + conn->hostname, conn->port, crTCPIPErrorString( err ) ); + + else if ( err == EINTR ) + { + crWarning( "connection to %s:%d " + "interruped, trying again", conn->hostname, conn->port ); + continue; + } + else + crWarning( "Couldn't connect to %s:%d, %s", + conn->hostname, conn->port, crTCPIPErrorString( err ) ); + cur=cur->ai_next; + } + + freeaddrinfo(res); + if (!cur) { + crWarning( "Couln't find any suitable way to connect to %s", conn->hostname ); + return 0; + } + + // read its UDP port + crTCPIPReadExact( conn->tcp_socket, &port, sizeof( port ) ); + port = ntohs(port); + + crDebug( "Server's UDP port is %d", port); + + // and connect to it + sprintf(port_s, "%u", port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF; + hints.ai_socktype = SOCK_DGRAM; + + err = getaddrinfo( conn->hostname, port_s, &hints, &res); + if ( err ) + { + crWarning( "Unknown host: \"%s\": %s", conn->hostname, gai_strerror(err) ); + return 0; + } + + for (cur=res;cur;) + { + conn->udp_socket = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + if ( conn->udp_socket >= 0 ) + { +#ifdef LINUX + int opt = IP_PMTUDISC_DO; +#endif + if ( connect( conn->udp_socket, cur->ai_addr, cur->ai_addrlen ) == -1 ) + crWarning( "Couldn't connect UDP socket : %s", crTCPIPErrorString( crTCPIPErrno( ) ) ); +#ifdef LINUX + if ( setsockopt(conn->udp_socket, SOL_IP, IP_MTU_DISCOVER, &opt, sizeof(opt)) == -1 ) + { + err = crTCPIPErrno( ); + crWarning( "MTU discovery can't be activated : %s", crTCPIPErrorString( err ) ); + } + else + { + socklen_t len = sizeof(opt); + if ( getsockopt(conn->udp_socket, SOL_IP, IP_MTU, &opt, &len) == -1 ) + crWarning( "MTU couldn't be got : %s", crTCPIPErrorString( crTCPIPErrno ( ) ) ); + else + if ( len != sizeof(opt) ) + crWarning( "Unexpected length %d for MTU option length", len ); + else + { + opt -= sizeof(conn->seq) + sizeof(struct udphdr) + sizeof(struct ip6_hdr); + crDebug( "MTU is (for now) %d", opt ); + conn->mtu = opt; + } + } +#endif + crMemcpy(&conn->remoteaddr, cur->ai_addr, cur->ai_addrlen); + freeaddrinfo(res); + return 1; + } + err = crTCPIPErrno( ); + if (err != EAFNOSUPPORT) + crWarning( "socket error: %s, trying another way", crTCPIPErrorString( err ) ); + cur=cur->ai_next; + } + freeaddrinfo(res); + crWarning( "Couldn't find any suitable way to connect to %s:%d", conn->hostname, port ); + return 0; +} + +static void crUDPTCPIPDoDisconnect( CRConnection *conn ) +{ + crCloseSocket( conn->tcp_socket ); + crCloseSocket( conn->udp_socket ); + conn->tcp_socket = 0; + conn->type = CR_NO_CONNECTION; + cr_udptcpip.conns[conn->index] = NULL; +} + +void crUDPTCPIPConnection( CRConnection *conn ) +{ + int i, found = 0; + int n_bytes; + + CRASSERT( cr_udptcpip.initialized ); + + srandom(time(NULL)); + conn->type = CR_UDPTCPIP; + conn->Alloc = crUDPTCPIPAlloc; + conn->Send = crUDPTCPIPSend; + conn->Barf = crUDPTCPIPBarf; + conn->SendExact = NULL; + conn->Recv = NULL; // none for UDP : *must* multiplex ! + conn->Free = crUDPTCPIPFree; + conn->Accept = crUDPTCPIPAccept; + conn->Connect = crUDPTCPIPDoConnect; + conn->Disconnect = crUDPTCPIPDoDisconnect; + conn->InstantReclaim = crUDPTCPIPInstantReclaim; + conn->HandleNewMessage = crUDPTCPIPHandleNewMessage; + conn->seq = 0; + conn->udp_packet = NULL; + conn->mtu = conn->mtu - sizeof(conn->seq); // some room for seq + conn->index = cr_udptcpip.num_conns; + conn->sizeof_buffer_header = sizeof( CRUDPTCPIPBuffer ); + + /* Find a free slot */ + for (i = 0; i < cr_udptcpip.num_conns; i++) { + if (cr_udptcpip.conns[i] == NULL) { + conn->index = i; + cr_udptcpip.conns[i] = conn; + found = 1; + break; + } + } + + /* Realloc connection stack if we couldn't find a free slot */ + if (found == 0) { + n_bytes = ( cr_udptcpip.num_conns + 1 ) * sizeof(*cr_udptcpip.conns); + crRealloc( (void **) &cr_udptcpip.conns, n_bytes ); + cr_udptcpip.conns[cr_udptcpip.num_conns++] = conn; + } +}