00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "rspConnection.h"
00020
00021 #ifdef EQ_USE_BOOST
00022 #include "connection.h"
00023 #include "connectionDescription.h"
00024 #include "global.h"
00025 #include "log.h"
00026
00027 #include <eq/base/rng.h>
00028 #include <eq/base/sleep.h>
00029
00030 #include <boost/bind.hpp>
00031
00032
00033 #define EQ_RSP_MERGE_WRITES
00034 #define EQ_RSP_MAX_TIMEOUTS 2000
00035
00036 using namespace boost::asio;
00037
00038 namespace eq
00039 {
00040 namespace net
00041 {
00042
00043 namespace
00044 {
00045 #ifdef EQ_INSTRUMENT_RSP
00046 base::a_int32_t nReadData;
00047 base::a_int32_t nBytesRead;
00048 base::a_int32_t nBytesWritten;
00049 base::a_int32_t nDatagrams;
00050 base::a_int32_t nRepeated;
00051 base::a_int32_t nMergedDatagrams;
00052 base::a_int32_t nAckRequests;
00053 base::a_int32_t nAcksSend;
00054 base::a_int32_t nAcksSendTotal;
00055 base::a_int32_t nAcksRead;
00056 base::a_int32_t nAcksAccepted;
00057 base::a_int32_t nNAcksSend;
00058 base::a_int32_t nNAcksRead;
00059 base::a_int32_t nNAcksResend;
00060
00061 float writeWaitTime = 0.f;
00062 base::Clock instrumentClock;
00063 #endif
00064
00065 static uint16_t _numBuffers = 0;
00066 }
00067
00068 RSPConnection::RSPConnection()
00069 : _id( 0 )
00070 , _idAccepted( false )
00071 , _mtu( Global::getIAttribute( Global::IATTR_UDP_MTU ))
00072 , _ackFreq( Global::getIAttribute( Global::IATTR_RSP_ACK_FREQUENCY ))
00073 , _payloadSize( _mtu - sizeof( DatagramData ))
00074 , _timeouts( 0 )
00075 , _event( new EventConnection )
00076 , _read( 0 )
00077 , _write( 0 )
00078 , _timeout( _ioService )
00079 , _wakeup( _ioService )
00080 , _maxBucketSize( ( _mtu * _ackFreq) >> 1 )
00081 , _bucketSize( 0 )
00082 , _sendRate( 0 )
00083 , _thread ( 0 )
00084 , _acked( std::numeric_limits< uint16_t >::max( ))
00085 , _threadBuffers( Global::getIAttribute( Global::IATTR_RSP_NUM_BUFFERS))
00086 , _recvBuffer( _mtu )
00087 , _readBuffer( 0 )
00088 , _readBufferPos( 0 )
00089 , _sequence( 0 )
00090 {
00091 _buildNewID();
00092 _description->type = CONNECTIONTYPE_RSP;
00093 _description->bandwidth = 102400;
00094
00095 EQCHECK( _event->connect( ));
00096
00097 _buffers.reserve( Global::getIAttribute( Global::IATTR_RSP_NUM_BUFFERS ));
00098 while( static_cast< int32_t >( _buffers.size( )) <
00099 Global::getIAttribute( Global::IATTR_RSP_NUM_BUFFERS ))
00100 {
00101 _buffers.push_back( new Buffer( _mtu ));
00102 }
00103
00104 EQASSERT( sizeof( DatagramNack ) <= size_t( _mtu ));
00105 EQLOG( LOG_RSP ) << "New RSP connection, " << _buffers.size()
00106 << " buffers of " << _mtu << " bytes" << std::endl;
00107 }
00108
00109 RSPConnection::~RSPConnection()
00110 {
00111 close();
00112 while( !_buffers.empty( ))
00113 {
00114 delete _buffers.back();
00115 _buffers.pop_back();
00116 }
00117 }
00118
00119 void RSPConnection::close()
00120 {
00121 if( _parent.isValid() && _parent->_id == _id )
00122 _parent->close();
00123
00124 while(( !_parent && _isWriting() ))
00125 {
00126 base::sleep( 10 );
00127 }
00128 _close();
00129 _event->set();
00130 }
00131
00132 void RSPConnection::_close()
00133 {
00134 if( _state == STATE_CLOSED )
00135 return;
00136 _state = STATE_CLOSING;
00137 base::ScopedMutex<> mutex( _mutexEvent );
00138
00139 if( _thread )
00140 {
00141 EQASSERT( !_thread->isCurrent( ));
00142 _sendSimpleDatagram( ID_EXIT, _id );
00143 _ioService.stop();
00144 _thread->join();
00145 _thread = 0;
00146
00147 for( RSPConnections::iterator i = _children.begin();
00148 i != _children.end(); ++i )
00149 {
00150 RSPConnectionPtr child = *i;
00151 base::ScopedMutex<> mutexChild( child->_mutexEvent );
00152 child->_appBuffers.push( 0 );
00153 child->_event->set();
00154 }
00155
00156 _children.clear();
00157 _childrenConnecting.clear();
00158 }
00159
00160 _parent = 0;
00161
00162 if( _read )
00163 _read->close();
00164 delete _read;
00165 _read = 0;
00166
00167 if( _write )
00168 _write->close();
00169 delete _write;
00170 _write = 0;
00171
00172 _threadBuffers.clear();
00173 _appBuffers.push( 0 );
00174
00175 _state = STATE_CLOSED;
00176 _fireStateChanged();
00177 }
00178
00179
00180
00181
00182 uint16_t RSPConnection::_buildNewID()
00183 {
00184 eq::base::RNG rng;
00185 _id = rng.get< uint16_t >();
00186 return _id;
00187 }
00188
00189 bool RSPConnection::listen()
00190 {
00191 EQASSERT( _description->type == CONNECTIONTYPE_RSP );
00192
00193 if( _state != STATE_CLOSED )
00194 return false;
00195
00196 _state = STATE_CONNECTING;
00197 _numBuffers = Global::getIAttribute( Global::IATTR_RSP_NUM_BUFFERS );
00198 _fireStateChanged();
00199
00200
00201 if( _description->port == 0 )
00202 _description->port = EQ_DEFAULT_PORT;
00203 if( _description->getHostname().empty( ))
00204 _description->setHostname( "239.255.42.43" );
00205 if( _description->getInterface().empty( ))
00206 _description->setInterface( "0.0.0.0" );
00207
00208 try
00209 {
00210 const ip::address readAddress( ip::address::from_string( "0.0.0.0" ));
00211 const ip::udp::endpoint readEndpoint( readAddress, _description->port );
00212
00213 const ip::address mcAddr(
00214 ip::address::from_string( _description->getHostname( )));
00215 const ip::udp::endpoint writeEndpoint( mcAddr, _description->port );
00216
00217 _read = new ip::udp::socket( _ioService );
00218 _write = new ip::udp::socket( _ioService );
00219 _read->open( readEndpoint.protocol( ));
00220 _write->open( writeEndpoint.protocol( ));
00221
00222 _read->set_option( ip::udp::socket::reuse_address( true ));
00223 _write->set_option( ip::udp::socket::reuse_address( true ));
00224 _read->set_option( ip::udp::socket::receive_buffer_size(
00225 Global::getIAttribute( Global::IATTR_UDP_BUFFER_SIZE )));
00226 _write->set_option( ip::udp::socket::send_buffer_size(
00227 Global::getIAttribute( Global::IATTR_UDP_BUFFER_SIZE )));
00228
00229 _read->bind( readEndpoint );
00230
00231 const ip::address ifAddr(
00232 ip::address::from_string( _description->getInterface( )));
00233
00234 _read->set_option( ip::multicast::join_group( mcAddr.to_v4(),
00235 ifAddr.to_v4( )));
00236 _write->set_option( ip::multicast::outbound_interface( ifAddr.to_v4()));
00237
00238 _write->connect( writeEndpoint );
00239
00240 _read->set_option( ip::multicast::enable_loopback( false ));
00241 _write->set_option( ip::multicast::enable_loopback( false ));
00242 }
00243 catch( boost::system::system_error& error )
00244 {
00245 EQWARN << "can't setup underlying UDP connection: " << error.what()
00246 << std::endl;
00247 delete _read;
00248 delete _write;
00249 _read = 0;
00250 _write = 0;
00251 return false;
00252 }
00253
00254
00255 _thread = new Thread( this );
00256 _bucketSize = 0;
00257 _sendRate = _description->bandwidth;
00258
00259
00260 if( !_thread->start( ) )
00261 {
00262 close();
00263 return false;
00264 }
00265
00266
00267 EQASSERT(_appBuffers.isEmpty());
00268 _appBuffers.push( _buffers );
00269
00270 _fireStateChanged();
00271
00272 EQINFO << "Listening on " << _description->getHostname() << ":"
00273 << _description->port << " (" << _description->toString() << " @"
00274 << (void*)this << ")" << std::endl;
00275 return true;
00276 }
00277
00278 ConnectionPtr RSPConnection::acceptSync()
00279 {
00280 if( _state != STATE_LISTENING )
00281 return 0;
00282
00283
00284 base::ScopedMutex<> mutexConn( _mutexConnection );
00285 EQASSERT( !_childrenConnecting.empty( ));
00286 if( _childrenConnecting.empty( ))
00287 return 0;
00288
00289 RSPConnectionPtr newConnection = _childrenConnecting.back();
00290 _childrenConnecting.pop_back();
00291 _children.push_back( newConnection );
00292 _sendDatagramCountNode();
00293
00294 EQINFO << "accepted RSP connection " << newConnection->_id << std::endl;
00295
00296 if ( !_childrenConnecting.empty() )
00297 _event->set();
00298 else
00299 _event->reset();
00300
00301 ConnectionPtr connection = newConnection.get();
00302 return connection;
00303 }
00304
00305 int64_t RSPConnection::readSync( void* buffer, const uint64_t bytes, const bool)
00306 {
00307 EQASSERT( bytes > 0 );
00308 if( _state != STATE_CONNECTED )
00309 return -1;
00310
00311 uint64_t bytesLeft = bytes;
00312 uint8_t* ptr = reinterpret_cast< uint8_t* >( buffer );
00313
00314
00315 while( bytesLeft )
00316 {
00317 if( !_readBuffer )
00318 {
00319 EQASSERT( _readBufferPos == 0 );
00320 _readBuffer = _appBuffers.pop();
00321 if( !_readBuffer )
00322 {
00323 close();
00324 return (bytes == bytesLeft) ?
00325 -1 : static_cast< int64_t >( bytes - bytesLeft );
00326 }
00327 }
00328 EQASSERT( _readBuffer );
00329
00330 const DatagramData* header = reinterpret_cast< const DatagramData* >(
00331 _readBuffer->getData( ));
00332 const uint8_t* payload = reinterpret_cast< const uint8_t* >( header+1 );
00333
00334 const size_t dataLeft = header->size - _readBufferPos;
00335 const size_t size = EQ_MIN( static_cast< size_t >( bytesLeft ),
00336 dataLeft );
00337
00338 memcpy( ptr, payload + _readBufferPos, size );
00339 _readBufferPos += size;
00340 ptr += size;
00341 bytesLeft -= size;
00342
00343
00344 if( _readBufferPos == header->size )
00345 {
00346
00347
00348
00349 EQCHECK( _threadBuffers.push( _readBuffer ));
00350 _readBuffer = 0;
00351 _readBufferPos = 0;
00352 }
00353 else
00354 {
00355 EQASSERT( _readBufferPos < header->size );
00356 }
00357 }
00358
00359 if( _readBuffer || !_appBuffers.isEmpty( ))
00360 _event->set();
00361 else
00362 {
00363 base::ScopedMutex<> mutex( _mutexEvent );
00364 if( _appBuffers.isEmpty( ))
00365 _event->reset();
00366
00367 }
00368
00369 #ifdef EQ_INSTRUMENT_RSP
00370 nBytesRead += bytes;
00371 #endif
00372 return bytes;
00373 }
00374
00375 void RSPConnection::Thread::run()
00376 {
00377 _connection->_runThread();
00378 _connection = 0;
00379 EQINFO << "Left RSP protocol thread" << std::endl;
00380 }
00381
00382 void RSPConnection::_handleTimeout( const boost::system::error_code& error )
00383 {
00384 if( error == boost::asio::error::operation_aborted )
00385 return;
00386
00387 if( _state == STATE_LISTENING )
00388 _handleConnectedTimeout();
00389 else if( _idAccepted )
00390 _handleInitTimeout();
00391 else
00392 _handleAcceptIDTimeout();
00393 }
00394
00395 void RSPConnection::_handleAcceptIDTimeout( )
00396 {
00397 ++_timeouts;
00398 if ( _timeouts < 20 )
00399 {
00400 EQLOG( LOG_RSP ) << "Announce " << _id << std::endl;
00401 _sendSimpleDatagram( ID_HELLO, _id );
00402 }
00403 else
00404 {
00405 EQLOG( LOG_RSP ) << "Confirm " << _id << std::endl;
00406 EQINFO << "opened RSP connection " << _id << std::endl;
00407 _sendSimpleDatagram( ID_CONFIRM, _id );
00408 _addNewConnection( _id );
00409 _idAccepted = true;
00410 _timeouts = 0;
00411
00412
00413 _sendDatagramCountNode();
00414 }
00415 _setTimeout( 10 );
00416 }
00417
00418 void RSPConnection::_handleInitTimeout( )
00419 {
00420 EQASSERT( _state != STATE_LISTENING );
00421 ++_timeouts;
00422 if( _timeouts < 20 )
00423 _sendDatagramCountNode();
00424 else
00425 {
00426 _state = STATE_LISTENING;
00427 _timeouts = 0;
00428 if( _children.empty() )
00429 _ioService.stop();
00430 }
00431 _setTimeout( 10 );
00432 }
00433
00434 void RSPConnection::_handleConnectedTimeout( )
00435 {
00436 if( _state != STATE_LISTENING )
00437 {
00438 _ioService.stop();
00439 return;
00440 }
00441
00442 _processOutgoing();
00443
00444 if( _timeouts >= EQ_RSP_MAX_TIMEOUTS )
00445 {
00446 EQERROR << "Too many timeouts during send: " << _timeouts << std::endl;
00447 _sendSimpleDatagram( ID_EXIT, _id );
00448 _appBuffers.pushFront( 0 );
00449 for( RSPConnections::iterator i = _children.begin();
00450 i != _children.end(); ++i )
00451 {
00452 RSPConnectionPtr child = *i;
00453 child->_state = STATE_CLOSING;
00454 child->_appBuffers.push( 0 );
00455 }
00456 _ioService.stop();
00457 }
00458 }
00459
00460 bool RSPConnection::_initThread()
00461 {
00462 EQINFO << "Started RSP protocol thread" << std::endl;
00463 _timeouts = 0;
00464
00465
00466 EQLOG( LOG_RSP ) << "Announce " << _id << std::endl;
00467 _sendSimpleDatagram( ID_HELLO, _id );
00468 _setTimeout( 10 );
00469 _asyncReceiveFrom();
00470 _ioService.run();
00471 return _state == STATE_LISTENING;
00472 }
00473
00474 void RSPConnection::_runThread()
00475 {
00476
00477 _ioService.reset();
00478 _ioService.run();
00479 }
00480
00481 void RSPConnection::_setTimeout( const int32_t timeOut )
00482 {
00483 EQASSERT( timeOut >= 0 );
00484 _timeout.expires_from_now( boost::posix_time::milliseconds( timeOut ));
00485 _timeout.async_wait( boost::bind( &RSPConnection::_handleTimeout, this,
00486 placeholders::error ));
00487 }
00488
00489 void RSPConnection::_postWakeup()
00490 {
00491 _wakeup.expires_from_now( boost::posix_time::milliseconds( 0 ));
00492 _wakeup.async_wait( boost::bind( &RSPConnection::_handleTimeout, this,
00493 placeholders::error ));
00494 }
00495
00496 void RSPConnection::_processOutgoing()
00497 {
00498 #ifdef EQ_INSTRUMENT_RSP
00499 if( instrumentClock.getTime64() > 1000 )
00500 {
00501 EQWARN << *this << std::endl;
00502 instrumentClock.reset();
00503 }
00504 #endif
00505
00506 if( !_repeatQueue.empty( ))
00507 _repeatData();
00508 else
00509 _writeData();
00510
00511 if( !_threadBuffers.isEmpty() || !_repeatQueue.empty( ))
00512 {
00513 _setTimeout( 0 );
00514 return;
00515 }
00516
00517
00518 if( _writeBuffers.empty( ))
00519 {
00520 _timeouts = 0;
00521 _timeout.cancel();
00522 return;
00523 }
00524
00525 const int64_t timeout =
00526 Global::getIAttribute( Global::IATTR_RSP_ACK_TIMEOUT );
00527 const int64_t left = timeout - _clock.getTime64();
00528
00529 if( left > 0 )
00530 {
00531 _setTimeout( left );
00532 return;
00533 }
00534
00535
00536 _clock.reset();
00537 ++_timeouts;
00538 _sendAckRequest();
00539 _setTimeout( timeout );
00540 }
00541
00542 void RSPConnection::_writeData()
00543 {
00544 Buffer* buffer = 0;
00545 if( !_threadBuffers.pop( buffer ))
00546 return;
00547
00548 _timeouts = 0;
00549 EQASSERT( buffer );
00550
00551
00552 DatagramData* header = reinterpret_cast<DatagramData*>( buffer->getData( ));
00553 header->sequence = _sequence++;
00554
00555 #ifdef EQ_RSP_MERGE_WRITES
00556 if( header->size < _payloadSize && !_threadBuffers.isEmpty( ))
00557 {
00558 std::vector< Buffer* > appBuffers;
00559 while( header->size < _payloadSize && !_threadBuffers.isEmpty( ))
00560 {
00561 Buffer* buffer2 = 0;
00562 EQCHECK( _threadBuffers.getFront( buffer2 ));
00563 EQASSERT( buffer2 );
00564 DatagramData* header2 =
00565 reinterpret_cast<DatagramData*>( buffer2->getData( ));
00566
00567 if( uint32_t( header->size + header2->size ) > _payloadSize )
00568 break;
00569
00570 memcpy( reinterpret_cast<uint8_t*>( header + 1 ) + header->size,
00571 header2 + 1, header2->size );
00572 header->size += header2->size;
00573 EQCHECK( _threadBuffers.pop( buffer2 ));
00574 appBuffers.push_back( buffer2 );
00575 #ifdef EQ_INSTRUMENT_RSP
00576 ++nMergedDatagrams;
00577 #endif
00578 }
00579
00580 if( !appBuffers.empty( ))
00581 _appBuffers.push( appBuffers );
00582 }
00583 #endif
00584
00585
00586
00587
00588
00589
00590 const uint32_t size = header->size + sizeof( DatagramData );
00591
00592 _waitWritable( size );
00593 _write->send( boost::asio::buffer( header, size ));
00594
00595 #ifdef EQ_INSTRUMENT_RSP
00596 ++nDatagrams;
00597 nBytesWritten += header->size;
00598 #endif
00599
00600
00601 _writeBuffers.push_back( buffer );
00602
00603 if( _children.size() == 1 )
00604 {
00605 EQASSERT( _children.front()->_id == _id );
00606 _finishWriteQueue( _sequence - 1 );
00607 }
00608 }
00609
00610 void RSPConnection::_waitWritable( const uint64_t bytes )
00611 {
00612 #ifdef EQ_INSTRUMENT_RSP
00613 base::Clock clock;
00614 #endif
00615
00616 _bucketSize += static_cast< uint64_t >( _clock.resetTimef() * _sendRate );
00617
00618 _bucketSize = EQ_MIN( _bucketSize, _maxBucketSize );
00619
00620 const uint64_t size = EQ_MIN( bytes, static_cast< uint64_t >( _mtu ));
00621 while( _bucketSize < size )
00622 {
00623
00624 base::Thread::yield();
00625 float time = _clock.resetTimef();
00626
00627 while( time == 0.f )
00628 {
00629 base::Thread::yield();
00630 time = _clock.resetTimef();
00631 }
00632
00633 _bucketSize += static_cast< int64_t >( time * _sendRate );
00634 _bucketSize = EQ_MIN( _bucketSize, _maxBucketSize );
00635 }
00636 _bucketSize -= size;
00637
00638 #ifdef EQ_INSTRUMENT_RSP
00639 writeWaitTime += clock.getTimef();
00640 #endif
00641
00642 if( _sendRate < _description->bandwidth )
00643 {
00644 _sendRate += int64_t(
00645 float( Global::getIAttribute( Global::IATTR_RSP_ERROR_UPSCALE )) *
00646 float( _description->bandwidth ) * .001f );
00647 EQLOG( LOG_RSP ) << "speeding up to " << _sendRate << " KB/s"
00648 << std::endl;
00649 }
00650 }
00651
00652 void RSPConnection::_repeatData()
00653 {
00654 _timeouts = 0;
00655
00656 while( !_repeatQueue.empty( ))
00657 {
00658 Nack& request = _repeatQueue.front();
00659 const uint16_t distance = _sequence - request.start;
00660 EQASSERT( distance != 0 );
00661
00662 if( distance <= _writeBuffers.size( ))
00663 {
00664
00665
00666
00667 const size_t i = _writeBuffers.size() - distance;
00668 Buffer* buffer = _writeBuffers[i];
00669 EQASSERT( buffer );
00670
00671 DatagramData* header =
00672 reinterpret_cast<DatagramData*>( buffer->getData( ));
00673 const uint32_t size = header->size + sizeof( DatagramData );
00674 EQASSERT( header->sequence == request.start );
00675
00676
00677 _waitWritable( size );
00678 _write->send( boost::asio::buffer( header, size ) );
00679 #ifdef EQ_INSTRUMENT_RSP
00680 ++nRepeated;
00681 #endif
00682 }
00683
00684 if( request.start == request.end )
00685 _repeatQueue.pop_front();
00686 else
00687 ++request.start;
00688
00689 if( distance <= _writeBuffers.size( ))
00690 return;
00691 }
00692 }
00693
00694 void RSPConnection::_finishWriteQueue( const uint16_t sequence )
00695 {
00696 EQLOG( LOG_RSP ) << "Got all remote acks for " << sequence << " current "
00697 << _sequence << std::endl;
00698 EQASSERT( !_writeBuffers.empty( ));
00699
00700 RSPConnectionPtr connection = _findConnection( _id );
00701 EQASSERT( connection.isValid( ));
00702 EQASSERT( connection->_recvBuffers.empty( ));
00703
00704
00705 Buffers readBuffers;
00706 Buffers freeBuffers;
00707
00708 const uint16_t size = _sequence - sequence - 1;
00709 EQASSERTINFO( size <= uint16_t( _writeBuffers.size( )),
00710 size << " > " << _writeBuffers.size( ));
00711
00712 while( _writeBuffers.size() > size_t( size ))
00713 {
00714 Buffer* buffer = _writeBuffers.front();
00715 _writeBuffers.pop_front();
00716
00717 #ifndef NDEBUG
00718 const DatagramData* datagram =
00719 reinterpret_cast< const DatagramData* >( buffer->getData( ));
00720 EQASSERT( datagram->writerID == _id );
00721 EQASSERTINFO( datagram->sequence ==
00722 uint16_t( connection->_sequence + readBuffers.size( )),
00723 datagram->sequence << ", " << connection->_sequence <<
00724 ", " << readBuffers.size( ));
00725
00726 #endif
00727
00728 Buffer* newBuffer = connection->_newDataBuffer( *buffer );
00729 if( !newBuffer && !readBuffers.empty( ))
00730 {
00731 base::ScopedMutex<> mutex( connection->_mutexEvent );
00732 EQLOG( LOG_RSP ) << "post " << readBuffers.size()
00733 << " buffers starting with sequence "
00734 << connection->_sequence << std::endl;
00735
00736 connection->_appBuffers.push( readBuffers );
00737 connection->_sequence += readBuffers.size();
00738 readBuffers.clear();
00739 connection->_event->set();
00740 }
00741
00742 while( !newBuffer )
00743 {
00744 newBuffer = connection->_newDataBuffer( *buffer );
00745
00746 base::Thread::yield();
00747 }
00748
00749 freeBuffers.push_back( buffer );
00750 readBuffers.push_back( newBuffer );
00751 }
00752
00753 _appBuffers.push( freeBuffers );
00754 if( !readBuffers.empty( ))
00755 {
00756 base::ScopedMutex<> mutex( connection->_mutexEvent );
00757 #if 0
00758 EQLOG( LOG_RSP )
00759 << "post " << readBuffers.size() << " buffers starting at "
00760 << connection->_sequence << std::endl;
00761 #endif
00762
00763 connection->_appBuffers.push( readBuffers );
00764 connection->_sequence += readBuffers.size();
00765 connection->_event->set();
00766 }
00767
00768 connection->_acked = uint16_t( connection->_sequence - 1 );
00769 EQASSERT( connection->_acked == sequence );
00770
00771 _timeouts = 0;
00772 }
00773
00774 void RSPConnection::_handlePacket( const boost::system::error_code& ,
00775 const size_t )
00776 {
00777 if( _state == STATE_LISTENING )
00778 {
00779 _handleConnectedData( _recvBuffer.getData() );
00780
00781 if( _state == STATE_LISTENING )
00782 _processOutgoing();
00783 else
00784 {
00785 _ioService.stop();
00786 return;
00787 }
00788 }
00789 else if( _idAccepted )
00790 _handleInitData( _recvBuffer.getData() );
00791 else
00792 _handleAcceptIDData( _recvBuffer.getData() );
00793
00794
00795 _asyncReceiveFrom();
00796 }
00797
00798 void RSPConnection::_handleAcceptIDData( const void* data )
00799 {
00800 const uint16_t type = *reinterpret_cast< const uint16_t* >( data );
00801 const DatagramNode* node =
00802 reinterpret_cast< const DatagramNode* >( data );
00803 switch( type )
00804 {
00805 case ID_HELLO:
00806 _checkNewID( node->connectionID );
00807 break;
00808
00809 case ID_DENY:
00810
00811 if( node->connectionID == _id )
00812 {
00813 _timeouts = 0;
00814 _sendSimpleDatagram( ID_HELLO, _buildNewID() );
00815 EQLOG( LOG_RSP ) << "Announce " << _id << std::endl;
00816 }
00817 break;
00818
00819 case ID_EXIT:
00820 _removeConnection( node->connectionID );
00821 break;
00822
00823 default:
00824 break;
00825 }
00826 }
00827
00828 void RSPConnection::_handleInitData( const void* data)
00829 {
00830 const uint16_t type = *reinterpret_cast< const uint16_t* >( data );
00831 const DatagramNode* node = reinterpret_cast< const DatagramNode* >( data );
00832 switch( type )
00833 {
00834 case ID_HELLO:
00835 _timeouts = 0;
00836 _checkNewID( node->connectionID ) ;
00837 return;
00838
00839 case ID_CONFIRM:
00840 _timeouts = 0;
00841 _addNewConnection( node->connectionID );
00842 return;
00843
00844 case COUNTNODE:
00845 if( _handleCountNode( ))
00846 _state = STATE_LISTENING;
00847 break;
00848
00849 case ID_EXIT:
00850 _removeConnection( node->connectionID );
00851 return;
00852
00853 default:
00854 EQUNIMPLEMENTED;
00855 break;
00856 }
00857 }
00858 void RSPConnection::_handleConnectedData( const void* data )
00859 {
00860 const uint16_t type = *reinterpret_cast< const uint16_t* >( data );
00861 switch( type )
00862 {
00863 case DATA:
00864 EQCHECK( _handleData( _recvBuffer ));
00865 break;
00866
00867 case ACK:
00868 EQCHECK( _handleAck(
00869 reinterpret_cast< const DatagramAck* >( data )));
00870 break;
00871
00872 case NACK:
00873 EQCHECK( _handleNack(
00874 reinterpret_cast< const DatagramNack* >( data )));
00875 break;
00876
00877 case ACKREQ:
00878 EQCHECK( _handleAckRequest(
00879 reinterpret_cast< const DatagramAckRequest* >( data )));
00880 break;
00881
00882 case ID_HELLO:
00883 {
00884 const DatagramNode* node =
00885 reinterpret_cast< const DatagramNode* >( data );
00886 _checkNewID( node->connectionID );
00887 break;
00888 }
00889
00890 case ID_CONFIRM:
00891 {
00892 const DatagramNode* node =
00893 reinterpret_cast< const DatagramNode* >( data );
00894 _addNewConnection( node->connectionID );
00895 break;
00896 }
00897
00898 case ID_EXIT:
00899 {
00900 const DatagramNode* node =
00901 reinterpret_cast< const DatagramNode* >( data );
00902 _removeConnection( node->connectionID );
00903 break;
00904 }
00905
00906 case COUNTNODE:
00907 _handleCountNode();
00908 break;
00909
00910 default:
00911 EQASSERTINFO( false,
00912 "Don't know how to handle packet of type " <<
00913 type );
00914 }
00915
00916 }
00917
00918 void RSPConnection::_asyncReceiveFrom()
00919 {
00920 _read->async_receive_from(
00921 buffer( _recvBuffer.getData(), _mtu ), _readAddr,
00922 boost::bind( &RSPConnection::_handlePacket, this,
00923 placeholders::error,
00924 placeholders::bytes_transferred ));
00925 }
00926
00927 bool RSPConnection::_handleData( Buffer& buffer )
00928 {
00929 #ifdef EQ_INSTRUMENT_RSP
00930 ++nReadData;
00931 #endif
00932 const DatagramData* datagram =
00933 reinterpret_cast< const DatagramData* >( buffer.getData( ));
00934 const uint16_t writerID = datagram->writerID;
00935 #ifdef Darwin
00936
00937
00938 if( writerID == _id )
00939 return true;
00940 #else
00941 EQASSERT( writerID != _id );
00942 #endif
00943
00944 RSPConnectionPtr connection = _findConnection( writerID );
00945
00946 if( !connection )
00947 {
00948 EQASSERTINFO( false, "Can't find connection with id " << writerID );
00949 return false;
00950 }
00951 EQASSERT( connection->_id == writerID );
00952
00953 const uint16_t sequence = datagram->sequence;
00954
00955
00956 if( connection->_sequence == sequence )
00957 {
00958 Buffer* newBuffer = connection->_newDataBuffer( buffer );
00959 if( !newBuffer )
00960 return true;
00961
00962 base::ScopedMutex<> mutex( connection->_mutexEvent );
00963 connection->_pushDataBuffer( newBuffer );
00964
00965 while( !connection->_recvBuffers.empty( ))
00966 {
00967 newBuffer = connection->_recvBuffers.front();
00968 if( !newBuffer )
00969 break;
00970
00971 connection->_recvBuffers.pop_front();
00972 connection->_pushDataBuffer( newBuffer );
00973 }
00974
00975 if( !connection->_recvBuffers.empty() &&
00976 !connection->_recvBuffers.front( ))
00977 {
00978 connection->_recvBuffers.pop_front();
00979 }
00980
00981 connection->_event->set();
00982 return true;
00983 }
00984
00985 if( connection->_sequence > sequence ||
00986 uint16_t( connection->_sequence - sequence ) <= _numBuffers )
00987 {
00988
00989 return true;
00990 }
00991
00992
00993
00994 const uint16_t size = sequence - connection->_sequence;
00995 EQASSERT( size != 0 );
00996 EQASSERTINFO( size <= _numBuffers, size << " > " << _numBuffers );
00997
00998 ssize_t i = ssize_t( size ) - 1;
00999 const bool gotPacket = ( connection->_recvBuffers.size() >= size &&
01000 connection->_recvBuffers[ i ] );
01001 if( gotPacket )
01002 return true;
01003
01004 Buffer* newBuffer = connection->_newDataBuffer( buffer );
01005 if( !newBuffer )
01006 return true;
01007
01008 if( connection->_recvBuffers.size() < size )
01009 connection->_recvBuffers.resize( size, 0 );
01010
01011 EQASSERT( !connection->_recvBuffers[ i ] );
01012 connection->_recvBuffers[ i ] = newBuffer;
01013
01014
01015 --i;
01016 Nack nack = { connection->_sequence, sequence - 1 };
01017 if( i > 0 )
01018 {
01019 if( connection->_recvBuffers[i] )
01020 return true;
01021
01022 while( i >= 0 && !connection->_recvBuffers[i] )
01023 --i;
01024
01025 const Buffer* lastBuffer = i>=0 ? connection->_recvBuffers[i] : 0;
01026 if( lastBuffer )
01027 {
01028 const DatagramData* last =
01029 reinterpret_cast<const DatagramData*>( lastBuffer->getData( ));
01030 nack.start = last->sequence + 1;
01031 }
01032 }
01033
01034 EQLOG( LOG_RSP ) << "send early nack " << nack.start << ".." << nack.end
01035 << " current " << connection->_sequence << " ooo "
01036 << connection->_recvBuffers.size() << std::endl;
01037
01038 if( nack.end < nack.start )
01039
01040 nack.end = std::numeric_limits< uint16_t >::max();
01041
01042 _sendNack( writerID, &nack, 1 );
01043 return true;
01044 }
01045
01046 RSPConnection::Buffer* RSPConnection::_newDataBuffer( Buffer& inBuffer )
01047 {
01048 EQASSERT( static_cast< int32_t >( inBuffer.getMaxSize( )) == _mtu );
01049
01050 Buffer* buffer = 0;
01051 if( !_threadBuffers.pop( buffer ))
01052 {
01053
01054
01055
01056
01057 EQLOG( LOG_RSP ) << "Reader too slow, dropping data" << std::endl;
01058 return 0;
01059 }
01060
01061 buffer->swap( inBuffer );
01062 return buffer;
01063 }
01064
01065 void RSPConnection::_pushDataBuffer( Buffer* buffer )
01066 {
01067 EQASSERT( _parent );
01068 EQASSERTINFO( ((DatagramData*)buffer->getData( ))->sequence == _sequence,
01069 ((DatagramData*)buffer->getData( ))->sequence << " != " <<
01070 _sequence );
01071
01072 if( (( _sequence + _id ) % _ackFreq ) == 0 )
01073 _parent->_sendAck( _id, _sequence );
01074
01075 EQLOG( LOG_RSP ) << "post buffer " << _sequence << std::endl;
01076 ++_sequence;
01077 _appBuffers.push( buffer );
01078 }
01079
01080 bool RSPConnection::_handleAck( const DatagramAck* ack )
01081 {
01082 #ifdef EQ_INSTRUMENT_RSP
01083 ++nAcksRead;
01084 #endif
01085
01086 if ( ack->writerID != _id )
01087 return true;
01088
01089 EQLOG( LOG_RSP ) << "got ack from " << ack->readerID << " for "
01090 << ack->writerID << " sequence " << ack->sequence
01091 << " current " << _sequence << std::endl;
01092
01093
01094
01095 RSPConnectionPtr connection = _findConnection( ack->readerID );
01096 if( !connection )
01097 {
01098 EQUNREACHABLE;
01099 return false;
01100 }
01101
01102 if( connection->_acked >= ack->sequence &&
01103 connection->_acked - ack->sequence <= _numBuffers )
01104 {
01105
01106 EQLOG( LOG_RSP ) << "Late ack" << std::endl;
01107 return true;
01108 }
01109
01110 #ifdef EQ_INSTRUMENT_RSP
01111 ++nAcksAccepted;
01112 #endif
01113 connection->_acked = ack->sequence;
01114 _timeouts = 0;
01115
01116
01117 for( std::vector< RSPConnectionPtr >::iterator i = _children.begin();
01118 i != _children.end(); ++i )
01119 {
01120 RSPConnectionPtr child = *i;
01121 if( child->_id == _id )
01122 continue;
01123
01124 const uint16_t distance = child->_acked - ack->sequence;
01125 if( distance > _numBuffers )
01126 return true;
01127 }
01128
01129 _finishWriteQueue( ack->sequence );
01130 return true;
01131 }
01132
01133 bool RSPConnection::_handleNack( const DatagramNack* nack )
01134 {
01135 #ifdef EQ_INSTRUMENT_RSP
01136 ++nNAcksRead;
01137 #endif
01138
01139 EQLOG( LOG_RSP )
01140 << "handle " << nack->count << " nacks from " << nack->readerID
01141 << " for " << nack->writerID << std::endl;
01142
01143 if( _id != nack->writerID )
01144 {
01145 EQLOG( LOG_RSP ) << "ignore nack, it's not for me" << std::endl;
01146 return true;
01147 }
01148
01149 RSPConnectionPtr connection = _findConnection( nack->readerID );
01150 if( !connection )
01151 {
01152 EQUNREACHABLE;
01153 return false;
01154
01155 }
01156
01157 _timeouts = 0;
01158 _addRepeat( nack->nacks, nack->count );
01159 return true;
01160 }
01161
01162 void RSPConnection::_addRepeat( const Nack* nacks, uint16_t num )
01163 {
01164 EQLOG( LOG_RSP ) << base::disableFlush << "Queue repeat requests ";
01165 size_t lost = 0;
01166
01167 for( size_t i = 0; i < num; ++i )
01168 {
01169 const Nack& nack = nacks[ i ];
01170 EQASSERT( nack.start <= nack.end );
01171
01172 EQLOG( LOG_RSP ) << nack.start << ".." << nack.end << " ";
01173
01174 bool merged = false;
01175 for( RepeatQueue::iterator j = _repeatQueue.begin();
01176 j != _repeatQueue.end() && !merged; ++j )
01177 {
01178 Nack& old = *j;
01179 if( old.start <= nack.end && old.end >= nack.start )
01180 {
01181 if( old.start > nack.start )
01182 {
01183 lost += old.start - nack.start;
01184 old.start = nack.start;
01185 merged = true;
01186 }
01187 if( old.end < nack.end )
01188 {
01189 lost += nack.end - old.end;
01190 old.end = nack.end;
01191 merged = true;
01192 }
01193 EQASSERT( lost < _numBuffers );
01194 }
01195 }
01196
01197 if( !merged )
01198 {
01199 lost += uint16_t( nack.end - nack.start ) + 1;
01200 EQASSERT( lost <= _numBuffers );
01201 _repeatQueue.push_back( nack );
01202 }
01203 }
01204
01205 if( _sendRate >
01206 ( _description->bandwidth >>
01207 Global::getIAttribute( Global::IATTR_RSP_MIN_SENDRATE_SHIFT )))
01208 {
01209 const float delta = float( lost ) * .001f *
01210 Global::getIAttribute( Global::IATTR_RSP_ERROR_DOWNSCALE );
01211 const float maxDelta = .01f *
01212 float( Global::getIAttribute( Global::IATTR_RSP_ERROR_MAXSCALE ));
01213 const float downScale = EQ_MIN( delta, maxDelta );
01214 _sendRate -= 1 + int64_t( _sendRate * downScale );
01215 EQLOG( LOG_RSP )
01216 << ", lost " << lost << " slowing down " << downScale * 100.f
01217 << "% to " << _sendRate << " KB/s" << std::endl <<base::enableFlush;
01218 }
01219 else
01220 EQLOG( LOG_RSP ) << std::endl << base::enableFlush;
01221 }
01222
01223 bool RSPConnection::_handleAckRequest( const DatagramAckRequest* ackRequest )
01224 {
01225 const uint16_t writerID = ackRequest->writerID;
01226 #ifdef Darwin
01227
01228
01229 if( writerID == _id )
01230 return true;
01231 #else
01232 EQASSERT( writerID != _id );
01233 #endif
01234 RSPConnectionPtr connection = _findConnection( writerID );
01235 if( !connection )
01236 {
01237 EQUNREACHABLE;
01238 return false;
01239 }
01240
01241 const uint16_t reqID = ackRequest->sequence;
01242 const uint16_t gotID = connection->_sequence - 1;
01243 const uint16_t distance = reqID - gotID;
01244
01245 EQLOG( LOG_RSP ) << "ack request " << reqID << " from " << writerID
01246 << " got " << gotID << " missing " << distance <<std::endl;
01247
01248 if( (reqID == gotID) ||
01249 (gotID > reqID && gotID - reqID <= _numBuffers) ||
01250 (gotID < reqID && distance > _numBuffers) )
01251 {
01252 _sendAck( connection->_id, gotID );
01253 return true;
01254 }
01255
01256
01257 const uint16_t max = EQ_RSP_MAX_NACKS - 2;
01258 Nack nacks[ EQ_RSP_MAX_NACKS ];
01259 uint16_t i = 0;
01260
01261 nacks[ i ].start = connection->_sequence;
01262 EQLOG( LOG_RSP ) << base::disableFlush << "nacks: " << nacks[i].start
01263 << "..";
01264
01265 std::deque<Buffer*>::const_iterator j = connection->_recvBuffers.begin();
01266 std::deque<Buffer*>::const_iterator first = j;
01267 for( ; j != connection->_recvBuffers.end() && i < max; ++j )
01268 {
01269 if( *j )
01270 {
01271 nacks[ i ].end = connection->_sequence + std::distance( first, j);
01272 EQLOG( LOG_RSP ) << nacks[i].end << ", ";
01273 if( nacks[ i ].end < nacks[ i ].start )
01274 {
01275 EQASSERT( nacks[ i ].end < _numBuffers );
01276 nacks[ i + 1 ].start = 0;
01277 nacks[ i + 1 ].end = nacks[ i ].end;
01278 nacks[ i ].end = std::numeric_limits< uint16_t >::max();
01279 ++i;
01280 }
01281 ++i;
01282
01283
01284 for( ++j; j != connection->_recvBuffers.end() && (*j); ++j )
01285 ;
01286
01287 if( j == connection->_recvBuffers.end( ))
01288 break;
01289
01290 nacks[i].start = connection->_sequence + std::distance(first, j) +1;
01291 EQLOG( LOG_RSP ) << nacks[i].start << "..";
01292 }
01293 }
01294
01295 if( j != connection->_recvBuffers.end() || i == 0 )
01296 {
01297 nacks[ i ].end = reqID;
01298 EQLOG( LOG_RSP ) << nacks[i].end;
01299 ++i;
01300 }
01301 else if( uint16_t( reqID - nacks[i-1].end ) < _numBuffers )
01302 {
01303 nacks[i].start = nacks[i-1].end + 1;
01304 nacks[i].end = reqID;
01305 EQLOG( LOG_RSP ) << nacks[i].start << ".." << nacks[i].end;
01306 ++i;
01307 }
01308 if( nacks[ i -1 ].end < nacks[ i - 1 ].start )
01309 {
01310 EQASSERT( nacks[ i - 1 ].end < _numBuffers );
01311 nacks[ i ].start = 0;
01312 nacks[ i ].end = nacks[ i - 1 ].end;
01313 nacks[ i - 1 ].end = std::numeric_limits< uint16_t >::max();
01314 ++i;
01315 }
01316
01317 EQLOG( LOG_RSP ) << std::endl << base::enableFlush << "send " << i
01318 << " nacks to " << connection->_id << std::endl;
01319
01320 EQASSERT( i > 0 );
01321 _sendNack( connection->_id, nacks, i );
01322 return true;
01323 }
01324
01325 bool RSPConnection::_handleCountNode()
01326 {
01327 const DatagramCount* countConn =
01328 reinterpret_cast< const DatagramCount* >( _recvBuffer.getData( ));
01329
01330 EQLOG( LOG_RSP ) << "Got " << countConn->numConnections << " nodes from "
01331 << countConn->clientID << std::endl;
01332
01333 if( _children.size() == countConn->numConnections )
01334 return true;
01335
01336 _addNewConnection( countConn->clientID );
01337 return false;
01338 }
01339
01340 void RSPConnection::_checkNewID( uint16_t id )
01341 {
01342
01343 if( id == _id || _findConnection( id ).isValid() )
01344 {
01345 EQLOG( LOG_RSP ) << "Deny " << id << std::endl;
01346 _sendSimpleDatagram( ID_DENY, _id );
01347 }
01348 }
01349
01350 RSPConnection::RSPConnectionPtr RSPConnection::_findConnection(
01351 const uint16_t id )
01352 {
01353 for( std::vector< RSPConnectionPtr >::const_iterator i = _children.begin();
01354 i != _children.end(); ++i )
01355 {
01356 if( (*i)->_id == id )
01357 return *i;
01358 }
01359 return 0;
01360 }
01361
01362
01363 bool RSPConnection::_addNewConnection( const uint16_t id )
01364 {
01365 if( _findConnection( id ).isValid() )
01366 return false;
01367
01368 base::ScopedMutex<> mutexConn( _mutexConnection );
01369 for( std::vector< RSPConnectionPtr >::const_iterator i = _children.begin();
01370 i != _children.end(); ++i )
01371 {
01372 if( (*i)->_id == id )
01373 return false;
01374 }
01375 for( std::vector< RSPConnectionPtr >::const_iterator i =
01376 _childrenConnecting.begin();
01377 i != _childrenConnecting.end(); ++i )
01378 {
01379 if( (*i)->_id == id )
01380 return false;
01381 }
01382
01383 RSPConnectionPtr connection = new RSPConnection();
01384 connection->_id = id;
01385 connection->_parent = this;
01386 connection->_state = STATE_CONNECTED;
01387 connection->_description = _description;
01388 EQASSERT( connection->_appBuffers.isEmpty( ));
01389
01390
01391 for( Buffers::iterator i = connection->_buffers.begin();
01392 i != connection->_buffers.end(); ++i )
01393 {
01394 Buffer* buffer = *i;
01395 EQCHECK( connection->_threadBuffers.push( buffer ));
01396 }
01397
01398 _childrenConnecting.push_back( connection );
01399 _event->set();
01400 return true;
01401 }
01402
01403 void RSPConnection::_removeConnection( const uint16_t id )
01404 {
01405 EQINFO << "remove connection " << id << std::endl;
01406 if( id == _id )
01407 return;
01408
01409 for( std::vector< RSPConnectionPtr >::iterator i = _children.begin();
01410 i != _children.end(); ++i )
01411 {
01412 RSPConnectionPtr child = *i;
01413 if( child->_id == id )
01414 {
01415 base::ScopedMutex<> mutex( _mutexEvent );
01416 _children.erase( i );
01417
01418 child->_appBuffers.push( 0 );
01419 child->_event->set();
01420 break;
01421 }
01422 }
01423
01424 _sendDatagramCountNode();
01425 }
01426
01427 int64_t RSPConnection::write( const void* inData, const uint64_t bytes )
01428 {
01429
01430 if ( _parent.isValid() )
01431 return _parent->write( inData, bytes );
01432
01433 EQASSERT( _state == STATE_LISTENING );
01434
01435 if ( !_write )
01436 return -1;
01437
01438
01439 uint64_t nDatagrams = bytes / _payloadSize;
01440 if ( nDatagrams * _payloadSize != bytes )
01441 ++nDatagrams;
01442
01443
01444 const uint8_t* data = reinterpret_cast< const uint8_t* >( inData );
01445 const uint8_t* end = data + bytes;
01446 for( uint64_t i = 0; i < nDatagrams; ++i )
01447 {
01448 size_t packetSize = end - data;
01449 packetSize = EQ_MIN( packetSize, _payloadSize );
01450
01451 if( _appBuffers.isEmpty( ))
01452
01453 _postWakeup();
01454
01455 Buffer* buffer = _appBuffers.pop();
01456 if( !buffer )
01457 {
01458 close();
01459 return -1;
01460 }
01461
01462
01463 DatagramData* header =
01464 reinterpret_cast< DatagramData* >( buffer->getData( ));
01465 header->type = DATA;
01466 header->size = uint16_t( packetSize );
01467 header->writerID = _id;
01468
01469 memcpy( header + 1, data, packetSize );
01470 data += packetSize;
01471
01472 EQCHECK( _threadBuffers.push( buffer ));
01473 }
01474 _postWakeup();
01475 EQLOG( LOG_RSP ) << "queued " << nDatagrams << " datagrams, "
01476 << bytes << " bytes" << std::endl;
01477 return bytes;
01478 }
01479
01480 void RSPConnection::_sendDatagramCountNode()
01481 {
01482 if ( !_findConnection( _id ) )
01483 return;
01484
01485 EQLOG( LOG_RSP ) << _children.size() << " nodes" << std::endl;
01486 const DatagramCount count = { COUNTNODE, _id,
01487 uint16_t( _children.size( ))};
01488 _write->send( buffer( &count, sizeof( count )) );
01489 }
01490
01491 void RSPConnection::_sendSimpleDatagram( DatagramType type, uint16_t id )
01492 {
01493 const DatagramNode simple = { type, id };
01494 _write->send( buffer( &simple, sizeof( simple )) );
01495 }
01496
01497 void RSPConnection::_sendAck( const uint16_t writerID,
01498 const uint16_t sequence )
01499 {
01500 EQASSERT( _id != writerID );
01501 #ifdef EQ_INSTRUMENT_RSP
01502 ++nAcksSend;
01503 #endif
01504
01505 EQLOG( LOG_RSP ) << "send ack " << sequence << std::endl;
01506 const DatagramAck ack = { ACK, _id, writerID, sequence };
01507 _write->send( buffer( &ack, sizeof( ack )) );
01508 }
01509
01510 void RSPConnection::_sendNack( const uint16_t writerID, const Nack* nacks,
01511 const uint16_t count )
01512 {
01513 EQASSERT( count > 0 );
01514 EQASSERT( count <= EQ_RSP_MAX_NACKS );
01515 #ifdef EQ_INSTRUMENT_RSP
01516 ++nNAcksSend;
01517 #endif
01518
01519 if( writerID == _id )
01520 {
01521 _addRepeat( nacks, count );
01522 return;
01523 }
01524
01525 const size_t size = sizeof( DatagramNack ) -
01526 (EQ_RSP_MAX_NACKS - count) * sizeof( Nack );
01527
01528
01529 DatagramNack packet;
01530 packet.set( _id, writerID, count );
01531 memcpy( packet.nacks, nacks, count * sizeof( Nack ));
01532 _write->send( buffer( &packet, size ));
01533 }
01534
01535 void RSPConnection::_sendAckRequest()
01536 {
01537 #ifdef EQ_INSTRUMENT_RSP
01538 ++nAckRequests;
01539 #endif
01540 EQLOG( LOG_RSP ) << "send ack request for " << uint16_t( _sequence -1 )
01541 << std::endl;
01542 const DatagramAckRequest ackRequest = { ACKREQ, _id, _sequence - 1 };
01543 _write->send( buffer( &ackRequest, sizeof( DatagramAckRequest )) );
01544 }
01545
01546 std::ostream& operator << ( std::ostream& os,
01547 const RSPConnection& connection )
01548 {
01549 os << base::disableFlush << base::disableHeader << "RSPConnection id "
01550 << connection.getID() << " send rate " << connection.getSendRate();
01551
01552 #ifdef EQ_INSTRUMENT_RSP
01553 const int prec = os.precision();
01554 os.precision( 3 );
01555
01556 const float time = instrumentClock.getTimef();
01557 const float mbps = 1048.576f * time;
01558 os << ": " << base::indent << std::endl
01559 << float( nBytesRead ) / mbps << " / " << float( nBytesWritten ) / mbps
01560 << " MB/s r/w using " << nDatagrams << " dgrams " << nRepeated
01561 << " repeats " << nMergedDatagrams
01562 << " merged"
01563 << std::endl;
01564
01565 os.precision( prec );
01566 os << "sender: " << nAckRequests << " ack requests " << nAcksAccepted << "/"
01567 << nAcksRead << " acks " << nNAcksRead << " nacks, throttle "
01568 << writeWaitTime << " ms"
01569 << std::endl
01570 << "receiver: " << nAcksSend << " acks " << nNAcksSend << " nacks"
01571 << base::exdent;
01572
01573 nReadData = 0;
01574 nBytesRead = 0;
01575 nBytesWritten = 0;
01576 nDatagrams = 0;
01577 nRepeated = 0;
01578 nMergedDatagrams = 0;
01579 nAckRequests = 0;
01580 nAcksSend = 0;
01581 nAcksRead = 0;
01582 nAcksAccepted = 0;
01583 nNAcksSend = 0;
01584 nNAcksRead = 0;
01585 writeWaitTime = 0.f;
01586 #endif
01587 os << std::endl << base::enableHeader << base::enableFlush;
01588
01589 return os;
01590 }
01591
01592 }
01593 }
01594 #endif //EQ_USE_BOOST