Exemple #1
0
////////////////////////////////////////////////////
// stream reset
void EQPacketStream::reset()
{
  resetCache();
  m_fragment.reset();
  m_arqSeqExp = 0;
  m_arqSeqFound = false;
}
void KisSelectionBasedLayer::setY(qint32 y)
{
    if (m_d->selection) {
        m_d->selection->setY(y);
        resetCache();
    }
}
Exemple #3
0
void Cache::initialize()
{
    Filter::initialize();

    resetCache();
    return;
}
void KisSelectionBasedLayer::setX(qint32 x)
{
    if (m_d->selection) {
        m_d->selection->setX(x);
        resetCache();
    }
}
Exemple #5
0
////////////////////////////////////////////////////
// stream reset
void EQPacketStream::reset()
{
  resetCache();
  m_fragment.reset();
  m_arqSeqExp = 0;
  m_arqSeqFound = false;
  m_sessionClientPort = 0;
  m_sessionId = 0;
  m_sessionKey = 0;
}
Exemple #6
0
void Outline::selectRoots()
//-------------------------
{
    OutlineRootSelect sel( this, _sentinel );

    if( sel.process() ) {
        scrollToSelected();
        resetCache();
        reset();
    }
}
Exemple #7
0
void Outline::resetOutline()
//--------------------------
// reset to initial state
{
    delete _sentinel;       // kill all elements
    _sentinel = new OutlineElement;
    resetCache();
    if( _findStack ) {
        _findStack->clear();
    }
}
Exemple #8
0
void BaseSynthEvent::calculateBuffers()
{
    if ( _locked )
    {
        _updateAfterUnlock = true;
        return;
    }

    int oldLength;

    if ( isSequenced )
    {
        _cancel = true;

        oldLength     = _sampleLength;
        _sampleLength = ( int )( length * ( float ) AudioEngine::bytes_per_tick );
        _sampleStart  = position * AudioEngine::bytes_per_tick;
        _sampleEnd    = _sampleStart + _sampleLength;
    }
    else {
        // quick releases of a noteOn-instruction should ring for at least a 64th note
        _minLength    = AudioEngine::bytes_per_bar / 64;
        _sampleLength = AudioEngine::bytes_per_bar;     // important for amplitude swell in
        oldLength     = AudioEngineProps::BUFFER_SIZE;  // buffer is as long as the engine's buffer size
        _hasMinLength = false;                          // keeping track if the min length has been rendered
    }

    _adsr->setBufferLength( _sampleLength );

    // sample length changed (f.i. tempo change) or buffer not yet created ?
    // create buffer for (new) sample length
    if ( _sampleLength != oldLength || _buffer == 0 )
    {
        // note that when event caching is enabled, the buffer is as large as
        // the total event length requires

        if ( AudioEngineProps::EVENT_CACHING && isSequenced )
        {
            destroyBuffer(); // clear previous buffer contents
            _buffer = new AudioBuffer( AudioEngineProps::OUTPUT_CHANNELS, _sampleLength );
        }
        else
            _buffer = new AudioBuffer( AudioEngineProps::OUTPUT_CHANNELS, AudioEngineProps::BUFFER_SIZE );
    }

    if ( AudioEngineProps::EVENT_CACHING && isSequenced )
    {
        resetCache(); // yes here, not in cache()-invocation as cancels might otherwise remain permanent (see BulkCacher)

        if ( _autoCache && !_caching ) // re-cache
            cache( false );
    }
}
Exemple #9
0
void FalseColorModel::setMultiImg(representation::t type,
								  SharedMultiImgPtr shared_img)
{
	// in the future, we might be interested in the other ones as well.
	// currently, we don't process other types, so "warn" the caller
	assert(type == representation::IMG || type == representation::GRAD);

	if (type == representation::IMG)
		this->shared_img = shared_img;
	else if (type == representation::GRAD)
		this->shared_grad = shared_img;

	resetCache();
}
Exemple #10
0
void Outline::toggleExpand( WWindow * )
//-------------------------------------
{
    OutlineElement * elm;

    elm = element( selected() );
    REQUIRE( elm != NULL, "Outline::toggleExpand" );

    if( elm->state() != OutlineElement::ESLeaf ) {
        elm->toggleExpand();
        resetCache();
        reset();    // paranoia
    }
}
Exemple #11
0
void Outline::findNext()
//----------------------
{
    BusyNotice busy( "Searching..." );
    OutlineElement * elm;
    int              i;

    elm = _findStack->removeLast();

    while( elm != NULL ) {
        _findStack->append( elm );
        if( elm->_child ) {
            elm = elm->_child;
        } else {
            elm = _findStack->removeLast(); // remove self from stack -- done

            while( elm->_lastSib ) {        // remove finished parents
                elm = _findStack->removeLast();
            }
            elm = elm->_sibling;
        }
        if( elm && _findFilter->matches( elm->symbol() ) ) {
            _findStack->append( elm );
            break;
        }
    }

    if( !elm ) {
        errMessage( "Not Found" );      // FIXME -- not an error, don't use errMessage
        _findStack->clear();
        menuManager()->enableMenu( MIMenuID(MMLocate,LMFindNext), false );
    } else {
        // expand all the parent nodes of this one (they are stored
        // in the find stack), but don't expand this node itself
        for( i = _findStack->entries() - 1; i > 0; i -= 1 ) {
            (*_findStack)[ i - 1 ]->expand( false );
        }
        for( i = 0; i < count(); i += 1 ) {
            if( elm == element( i ) ) {
                select( i );
            }
        }
        resetCache();
        reset();
        scrollToSelected();
        menuManager()->enableMenu( MIMenuID(MMLocate,LMFindNext), true );
    }
}
Exemple #12
0
OutlineElement * Outline::element( int index )
//--------------------------------------------
{
    if( _cacheIndex > index ) {
        resetCache();
    }

    while( (_cacheIndex < index) && (_cacheElement != NULL) ) {
        _cacheElement = _cacheElement->next();
        _cacheIndex += 1;
    }

    if( _cacheIndex == index ) {
        return _cacheElement;
    } else {
        return NULL;
    }
}
Exemple #13
0
Outline::Outline( const char * text )
        : HotWindowList( text )
        , GlobalViewTree( menuManager() )
        , _findStack( NULL )
//----------------------------------------------------------------
{
    _sentinel = new OutlineElement;
    _queryConfig = new QueryConfig( this, "Find" );
    _findFilter = new KeySymbol;
    _loadFilter = new KeySymbol( WBRWinBase::optManager()->getQueryFilt() );

    onHotPress( this, (cbw) &Outline::toggleExpand );
    onDblClick( this, (cbw) &Outline::detailView );
    onChanged( this, (cbw) &Outline::changed );

    menuManager()->trackPopup( this, MMTree );
    viewManager()->registerForEvents( this );

    resetCache();
}
Exemple #14
0
FalseColorModel::FalseColorModel(QObject *parent )
	: QObject(parent)
{
	int type = QMetaType::type("FalseColoring");
	if (type == 0 || !QMetaType::isRegistered(type))
		qRegisterMetaType<FalseColoring::Type>("FalseColoring");

	type = QMetaType::type("std::map<std::string, boost::any>");
	if (type == 0 || !QMetaType::isRegistered(type))
		qRegisterMetaType< std::map<std::string, boost::any> >(
					"std::map<std::string, boost::any>");

	foreach(FalseColoring::Type c, FalseColoring::all()) {
		pendingRequests[c] = false;
	}
	foreach(representation::t type, representation::all()) {
		representationInit[type] = false;
	}

	resetCache();
}
Exemple #15
0
void Outline::treeViewEvent( TreeViewEvent event )
//------------------------------------------------
{
    OutlineElement * elm;

    elm = element( selected() );

    switch( event ) {
    case ShowDetail:
        if( elm && elm->_symbol ) {
            popDetail( elm->_symbol );
        }
        break;
    case ShowDefinition:
        if( elm && elm->_symbol ) {
            browseTop->showSource( elm->_symbol );
        }
        break;
    case ShowReferences:
        if( elm && elm->_symbol ) {
            viewManager()->showDetailView( elm->_symbol, DetailView::ViewSourceRefs );
        }
        break;
    case ShowUsers:
        if( elm && elm->_symbol ) {
            viewManager()->showDetailView( elm->_symbol, DetailView::ViewSymbolRefs );
        }
        break;
    case ScrollToSelected:
        scrollToSelected();
        break;
    case SelectRoots:
        selectRoots();
        break;
    case ExpandOne:
        elm->expand( false );
        resetCache();
        reset();    // paranoia
        break;
    case ExpandBranch:
        elm->expand( true );
        resetCache();
        reset();    // paranoia
        break;
    case ExpandAll:
        for( elm = _sentinel->next(); elm != NULL; elm = elm->visibleSib() ) {
            elm->expand( true );
        }
        resetCache();
        reset();    // paranoia
        break;
    case CollapseBranch:
        if( elm->state() == OutlineElement::ESExpanded ) {
            elm->collapse( false );
            resetCache();
            reset();    // paranoia
        }
        break;
    case CollapseAll:
        for( elm = _sentinel->next(); elm != NULL; elm = elm->visibleSib() ) {
            elm->collapse( true );
        }
        resetCache();
        reset();    // paranoia
        break;
    default:
        NODEFAULT;
    }
}
Exemple #16
0
void CQBaseDataModel::setDataModel(CCopasiDataModel * pDataModel)
{
  mpDataModel = pDataModel;
  resetCache();
}
Exemple #17
0
bool CQBaseDataModel::clear()
{
  resetCache();
  return removeRows(0, rowCount() - 1);
}
Exemple #18
0
void SynthEvent::calculateBuffers()
{
    if ( _locked )
    {
        _updateAfterUnlock = true;
        return;
    }

    int oldLength;

    if ( isSequenced )
    {
        if ( _caching )
            _cancel = true;

        oldLength     = _sampleLength;
        _sampleLength = ( int )( length * ( float ) AudioEngine::bytes_per_tick );
        _sampleStart  = position * AudioEngine::bytes_per_tick;
        _sampleEnd    = _sampleStart + _sampleLength;
    }
    else {
        // quick releases of the key should at least ring for a 32nd note
        _minLength    = AudioEngine::bytes_per_bar / 32;
        _sampleLength = AudioEngine::bytes_per_bar;     // important for amplitude swell in
        oldLength     = AudioEngineProps::BUFFER_SIZE;  // buffer is as long as the engine's buffer size
        _hasMinLength = false;                          // keeping track if the min length has been rendered
    }

    _adsr->setBufferLength( _sampleLength );

    // sample length changed (f.i. tempo change) or buffer not yet created ?
    // create buffer for (new) sample length
    if ( _sampleLength != oldLength || _buffer == 0 )
    {
        destroyBuffer(); // clear previous buffer contents

        // OSC2 generates no buffer (writes into parent buffer, saves memory)
        if ( !hasParent )
        {
            // note that when event caching is enabled, the buffer is as large as
            // the total event length requires

            if ( AudioEngineProps::EVENT_CACHING && isSequenced )
                _buffer = new AudioBuffer( AudioEngineProps::OUTPUT_CHANNELS, _sampleLength );
            else
                _buffer = new AudioBuffer( AudioEngineProps::OUTPUT_CHANNELS, AudioEngineProps::BUFFER_SIZE );
        }
     }

    if ( isSequenced )
    {
        if ( _type == WaveForms::KARPLUS_STRONG )
            initKarplusStrong();

        if ( AudioEngineProps::EVENT_CACHING )
        {
            resetCache(); // yes here, not in cache()-invocation as cancels might otherwise remain permanent (see BulkCacher)

            // (re)cache (unless this event is OSC2 as only the parent event can invoke the render)
            if ( _autoCache && !hasParent )
            {
                if ( !_caching )
                    cache( false );
                else
                    _cancel = true;
            }
        }
    }
}
Exemple #19
0
void Cache::resetCache(boost::uint32_t maxCacheBlocks, boost::uint32_t cacheBlockSize)
{
    m_maxCacheBlocks = maxCacheBlocks;
    m_cacheBlockSize = cacheBlockSize;
    resetCache();
}
Exemple #20
0
void SynthEvent::calculateBuffers()
{
    // we override the entire function body as we need some
    // oscillator 2-specific operations in here

    if ( _locked )
    {
        _updateAfterUnlock = true;
        return;
    }
    int oldLength;

    if ( isSequenced )
    {
        _cancel = true;

        oldLength     = _sampleLength;
        _sampleLength = ( int )( length * ( float ) AudioEngine::bytes_per_tick );
        _sampleStart  = position * AudioEngine::bytes_per_tick;
        _sampleEnd    = _sampleStart + _sampleLength;
    }
    else {
        // quick releases of a noteOn-instruction should ring for at least a 64th note
        _minLength    = AudioEngine::bytes_per_bar / 64;
        _sampleLength = AudioEngine::bytes_per_bar;     // important for amplitude swell in
        oldLength     = AudioEngineProps::BUFFER_SIZE;  // buffer is as long as the engine's buffer size
        _hasMinLength = false;                          // keeping track if the min length has been rendered
    }

    _adsr->setBufferLength( _sampleLength );

    // sample length changed (f.i. tempo change) or buffer not yet created ? create buffer for (new) length

    if ( _sampleLength != oldLength )
    {
        if ( !hasParent ) // OSC2 generates no buffer (writes into parent buffer, saves memory)
        {
            // note that when event caching is enabled, the buffer is as large as
            // the total event length requires

            if ( AudioEngineProps::EVENT_CACHING && isSequenced )
            {
                destroyBuffer(); // clear previous buffer contents
                _buffer = new AudioBuffer( AudioEngineProps::OUTPUT_CHANNELS, _sampleLength );
            }
            else
                _buffer = new AudioBuffer( AudioEngineProps::OUTPUT_CHANNELS, AudioEngineProps::BUFFER_SIZE );

            // though this event manages its child oscillator, the render method needs these properties
            if ( _osc2 != 0 ) {
                _osc2->_sampleLength = _sampleLength;
                _osc2->_sampleStart  = _sampleStart;
                _osc2->_sampleEnd    = _sampleEnd;
            }
        }
    }

    if ( isSequenced )
    {
        if ( _type == WaveForms::KARPLUS_STRONG )
            initKarplusStrong();

        if ( AudioEngineProps::EVENT_CACHING )
        {
            resetCache(); // yes here, not in cache()-invocation as cancels might otherwise remain permanent (see BulkCacher)

            if ( _autoCache && !_caching ) // re-cache
                cache( false );
        }
    }
}
Exemple #21
0
int main() {
    resetCache();
    __int64 allSolutions = findOutSolutions(20,20);
    printf("There are %I64d solutions\n", allSolutions);
}
Exemple #22
0
/////////////////////////////////////////////////////
// Handle a protocol level packet. This could be either a top-level
// EQUDPIPPacket or a subpacket that is just an EQProtocolPacket. Either way
// we use net opcodes here.
void EQPacketStream::processPacket(EQProtocolPacket& packet, bool /*isSubpacket*/)
{
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
  seqDebug("-->EQPacketStream::processPacket, subpacket=%s on stream %s (%d)",
    (isSubpacket ? "true" : "false"), EQStreamStr[m_streamid], m_streamid);
#endif

  if (IS_APP_OPCODE(packet.getNetOpCode()))
  {
    // This is an app-opcode directly on the wire with no wrapping protocol
    // information. Weird, but whatever gets the stream read, right?
	dispatchPacket(packet.payload(), packet.payloadLength(), 
      packet.getNetOpCode(), m_opcodeDB.find(packet.getNetOpCode()));
    return;
  }

  // Process the net opcode
  switch (packet.getNetOpCode())
  {
    case OP_Combined:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: found combined packet (net op: %04x, size %d) on stream %s (%d). Unrolling.", 
        packet.getNetOpCode(), packet.payloadLength(), 
        EQStreamStr[m_streamid], m_streamid);
#endif

      // Rolled up multiple packets inside this packet. Need to unroll them
      // and process them individually. subpacket starts after the net opcode.
      uint8_t* subpacket = packet.payload();

      while (subpacket < packet.payload() + packet.payloadLength())
      {
        // Length specified first on the wire.
        uint8_t subpacketLength = subpacket[0];

        // Move past the length
        subpacket++;

        // OpCode (in net order)
        uint16_t subOpCode = *(uint16_t*)subpacket;
        
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: unrolling length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif
        
        // Opcode is next. Net opcode or app opcode?
        if (subOpCode == 0)
        {
          // App opcode < 0x00ff. Skip the first byte and dispatch the app
          // opcode appropriately
          subpacket++;

          subOpCode = *(uint16_t*)subpacket;

#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
          seqDebug("EQPacket: processing unrolled special app opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
            subpacketLength-3, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // App opcode. Dispatch it, skipping opcode.
          dispatchPacket(&subpacket[2], subpacketLength-2, 
            subOpCode, m_opcodeDB.find(subOpCode));

        }
        else if (IS_NET_OPCODE(subOpCode))
        {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
          seqDebug("EQPacket: processing unrolled net opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
            subpacketLength, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // Net opcode. false = copy. true = subpacket
          EQProtocolPacket spacket(subpacket, subpacketLength, false, true);

          processPacket(spacket, true);
        }
        else
        {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: processing unrolled app opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength-2, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // App opcode. Dispatch it, skipping opcode.
          dispatchPacket(&subpacket[2], subpacketLength-2, 
            subOpCode, m_opcodeDB.find(subOpCode));
        }
        subpacket += subpacketLength;
      }
    }
    break;
    case OP_AppCombined:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: found appcombined packet (net op: %04x, size %d) on stream %s (%d). Unrolling.", 
        packet.getNetOpCode(), packet.payloadLength(), 
        EQStreamStr[m_streamid], m_streamid);
#endif

      // Multiple app op codes in the same packet. Need to unroll and dispatch
      // them.
      uint8_t* subpacket = packet.payload();

      while (subpacket < packet.payload() + packet.payloadLength())
      {
        // Length specified first on the wire.
        uint8_t subpacketLength = subpacket[0];

        // Move past the length
        subpacket++;

        if (subpacketLength != 0xff)
        {
          // Dispatch app op code using given packet length. Net order!
          uint16_t subOpCode = *(uint16_t*)(subpacket);

          // Handle 3 byte opcodes properly
          if (subOpCode == 0)
          {
            // 3 byte opcode. Drop the first byte, opcode is byte 2 and 3
            subpacket++;
            subpacketLength--;
            subOpCode = *(uint16_t*)(subpacket);
          }

#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: unrolling length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength, EQStreamStr[m_streamid], m_streamid, subOpCode);
        seqDebug("EQPacket: processing unrolled app opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength-2, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // Dispatch, skipping op code.
          dispatchPacket(&subpacket[2], subpacketLength-2, 
            subOpCode, m_opcodeDB.find(subOpCode));

          // Move ahead
          subpacket += subpacketLength;
        }
        else
        {
          // If original length is 0xff, it means it is a long one. The length
          // is 2 bytes and next.
          uint16_t longOne = eqntohuint16(subpacket);
 
          // Move past the 2 byte length
          subpacket += 2;

          // OpCode next. Net order for op codes.
          uint16_t subOpCode = *(uint16_t*)subpacket;

          // Handle 3 byte opcodes properly
          if (subOpCode == 0)
          {
            // 3 byte opcode. Drop the first byte, opcode is byte 2 and 3
            subpacket++;
            longOne--;
            subOpCode = *(uint16_t*)(subpacket);
          }
          
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: unrolling length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          longOne, EQStreamStr[m_streamid], m_streamid, subOpCode);
        seqDebug("EQPacket: processing unrolled app opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          longOne-2, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // Dispatch, skipping op code.
          dispatchPacket(&subpacket[2], longOne-2, 
            subOpCode, m_opcodeDB.find(subOpCode));

          // Move ahead
          subpacket += longOne;
        }
      }
    }
    break;
    case OP_Packet:
    {
      // Normal unfragmented sequenced packet.
      uint16_t seq = packet.arqSeq();
      emit seqReceive(seq, (int)m_streamid);

      // Future packet?
      if (seq == m_arqSeqExp)
      {
        // Expected packet.
        m_arqSeqExp++;
        emit seqExpect(m_arqSeqExp, (int)m_streamid);

        // OpCode next. Net order for op codes.
        uint16_t subOpCode = *(uint16_t*)(packet.payload());
       
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
        seqDebug("SEQ: Found next sequence number in data stream %s (%d), incrementing expected seq, %04x (op code %04x, sub opcode %04x)", 
          EQStreamStr[m_streamid], m_streamid, seq, 
          packet.getNetOpCode(), subOpCode);
#endif

        // Opcode is next. Net opcode or app opcode?
        if (subOpCode == 0)
        {
          // App opcode < 0x00ff. Skip the first byte and dispatch the app
          // opcode appropriately
          subOpCode = *(uint16_t*)&packet.payload()[1];

#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
          seqDebug("EQPacket: special app opcode extracted for opcode 0000 on stream %s (%d). Opcode %04x", 
            EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // App opcode. Dispatch it, skipping opcode.
          dispatchPacket(&packet.payload()[3], packet.payloadLength()-3, 
            subOpCode, m_opcodeDB.find(subOpCode));

        }
        else if (IS_NET_OPCODE(subOpCode))
        {
          // Net opcode. false = no copy. true = subpacket.
          EQProtocolPacket spacket(packet.payload(), 
            packet.payloadLength(), false, true);

          processPacket(spacket, true);
        }
        else
        {
          // App opcode. Dispatch, skipping opcode.
          dispatchPacket(&packet.payload()[2], packet.payloadLength()-2,
            subOpCode, m_opcodeDB.find(subOpCode));
        }
      }
      else if ((seq > m_arqSeqExp && 
                  seq < (uint32_t(m_arqSeqExp + arqSeqWrapCutoff))) ||
               seq < (int32_t(m_arqSeqExp) - arqSeqWrapCutoff))
      {
        // Yeah, future packet. Push it on the packet cache.
#ifdef PACKET_PROCESS_DIAG
        seqDebug("SEQ: out of order sequence %04x stream %s (%d) expecting %04x, sending to cache, %04d",
          seq, EQStreamStr[m_streamid], m_streamid, 
          m_arqSeqExp, m_cache.size());
#endif
        setCache(seq, packet);
      }
      else
      {
#ifdef PACKET_PROCESS_DIAG
        // Past packet outside the cut off
        seqWarn("SEQ: received sequenced %spacket outside expected window on stream %s (%d) netopcode=%04x size=%d. Expecting seq=%04x got seq=%04x, window size %d, dropping packet as in the past.", 
          (isSubpacket ? "sub" : ""),
          EQStreamStr[m_streamid], m_streamid,
          packet.getNetOpCode(), packet.payloadLength(), 
          m_arqSeqExp, seq, arqSeqWrapCutoff);
#endif
      }
    }
    break;
    case OP_Oversized:
    {
      // Fragmented sequenced data packet.
      uint16_t seq = packet.arqSeq();
      emit seqReceive(seq, (int)m_streamid);

      // Future packet?
      if (seq == m_arqSeqExp)
      {
        // Expected packet.
        m_arqSeqExp++;
        emit seqExpect(m_arqSeqExp, (int)m_streamid);
       
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
        seqDebug("SEQ: Found next sequence number in data stream %s (%d), incrementing expected seq, %04x (op code %04x)", 
          EQStreamStr[m_streamid], m_streamid, seq, packet.getNetOpCode());
#endif

        // Push the fragment on.
        m_fragment.addFragment(packet);

        if (m_fragment.isComplete())
        {
          // OpCode from fragment. In network order.
          uint16_t fragOpCode = *(uint16_t*)(m_fragment.data());

#ifdef PACKET_PROCESS_DIAG
        seqDebug("SEQ: Completed oversized app packet on stream %s with seq %04x, total size %d opcode %04x", 
          EQStreamStr[m_streamid], seq, m_fragment.size()-2, fragOpCode);
#endif

          // dispatch fragment. Skip opcode.
          if (fragOpCode == 0)
          {
            // Special app opcode. Skip first byte and op is byte 2 and 3.
            fragOpCode = *(uint16_t*)(&m_fragment.data()[1]);

#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
            seqDebug("EQPacket: special app opcode on completed fragment for opcode 0000 on stream %s (%d). Opcode %04x", 
            EQStreamStr[m_streamid], m_streamid, fragOpCode);
#endif

            dispatchPacket(&m_fragment.data()[3], m_fragment.size()-3,
              fragOpCode, m_opcodeDB.find(fragOpCode)); 
          }
          else
          {
            dispatchPacket(&m_fragment.data()[2], m_fragment.size()-2,
              fragOpCode, m_opcodeDB.find(fragOpCode)); 
          }

          m_fragment.reset();
        }
      }
      else if ((seq > m_arqSeqExp && 
                  seq < (uint32_t(m_arqSeqExp + arqSeqWrapCutoff))) ||
               seq < (int32_t(m_arqSeqExp) - arqSeqWrapCutoff))
      {
        // Yeah, future packet. Push it on the packet cache.
#ifdef PACKET_PROCESS_DIAG
        seqDebug("SEQ: out of order sequence %04x stream %s (%d) expecting %04x, sending to cache, %04d",
          seq, EQStreamStr[m_streamid], m_streamid, 
          m_arqSeqExp, m_cache.size());
#endif
        setCache(seq, packet);
      }
      else
      {
#ifdef PACKET_PROCESS_DIAG
        // Past packet outside the cut off
        seqWarn("SEQ: received sequenced %spacket outside expected window on stream %s (%d) netopcode=%04x size=%d. Expecting seq=%04x got seq=%04x, window size %d, dropping packet as in the past.", 
          (isSubpacket ? "sub" : ""),
          EQStreamStr[m_streamid], m_streamid,
          packet.getNetOpCode(), packet.payloadLength(), 
          m_arqSeqExp, seq, arqSeqWrapCutoff);
#endif
      }
    }
    break;
    case OP_SessionRequest:
    {
      // Session request from client to server.
      // 
      // Sanity check the size. Don't assume any packet we see is an EQ
      // session request, since we're gonna cause a huge freakin' malloc
      // on the maxlength of the session which for some reason some people
      // won't enjoy!
      if (packet.payloadLength() != sizeof(SessionRequestStruct))
      {
          // Either SessionRequestStruct changed or this isn't a session
          // request.
#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
          seqDebug("EQPacket: Ignoring SessionRequest %s:%u->%s:%u with invalid size %d.",
            ((EQUDPIPPacketFormat&) packet).getIPv4SourceA().ascii(),
            ((EQUDPIPPacketFormat&) packet).getSourcePort(),
            ((EQUDPIPPacketFormat&) packet).getIPv4DestA().ascii(),
            ((EQUDPIPPacketFormat&) packet).getDestPort(),
            packet.payloadLength());
#endif
          break;
      }

      // Pull off session request information
      SessionRequestStruct* request = (SessionRequestStruct*) packet.payload();

      m_sessionId = eqntohuint32((uint8_t*)&(request->sessionId));
      m_maxLength = eqntohuint32((uint8_t*)&(request->maxLength));

      // Sanity check the max length requested
      if (m_maxLength > maxPacketSize)
      {
        seqWarn("EQPacket: SessionRequest wanted a max packet size of %d which is above our sane max packet size of %d. Using our max",
          m_maxLength, maxPacketSize);

        m_maxLength = maxPacketSize;
      }

      emit maxLength((int) m_maxLength, (int) m_streamid);

#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionRequest found, resetting expected seq, stream %s (%d) (session tracking %s)",
	    EQStreamStr[m_streamid], m_streamid,
        (m_session_tracking_enabled == 2 ? "locked on" : 
          (m_session_tracking_enabled == 1 ? "enabled" : "disabled")));
#endif

#if defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionRequest %s:%u->%s:%u, sessionId %u maxLength %u, awaiting key for stream %s (%d)",
        ((EQUDPIPPacketFormat&) packet).getIPv4SourceA().ascii(),
        ((EQUDPIPPacketFormat&) packet).getSourcePort(),
        ((EQUDPIPPacketFormat&) packet).getIPv4DestA().ascii(),
        ((EQUDPIPPacketFormat&) packet).getDestPort(),
        m_sessionId, m_maxLength, EQStreamStr[m_streamid], m_streamid);
#endif

#if defined(PACKET_SESSION_DIAG) && (PACKET_SESSION_DIAG > 1)
      seqDebug("EQPacket: SessionRequest contents: unknown %u, sessionId %u, maxLength %u",
        eqntohuint32((uint8_t*)&(request->unknown0000)), 
        m_sessionId, m_maxLength);
#endif

#if defined(PACKET_SESSION_DIAG) && (PACKET_SESSION_DIAG > 2)
      seqDebug("EQPacket: Raw SessionRequest: %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x",
        packet.payload()[0], packet.payload()[1], packet.payload()[2], 
        packet.payload()[3], packet.payload()[4], packet.payload()[5], 
        packet.payload()[6], packet.payload()[7], packet.payload()[8], 
        packet.payload()[9], packet.payload()[10], packet.payload()[11]);
#endif

      m_arqSeqExp = 0;
      m_arqSeqFound = true;

      if (m_session_tracking_enabled)
      {
        // Save off client port for the stream so we can match against it
        // later. SessionRequest should always be an outer protocol packet
        // so we can cast it to EQUDPIPPacketFormat to get the ip headers.
        m_sessionClientPort = ((EQUDPIPPacketFormat&) packet).getSourcePort();
      }
    }
    break;
    case OP_SessionResponse:
    {
      // Session response from server

      // Sanity check the size. Don't assume any packet we see is an EQ
      // session response, since we're gonna cause a huge freakin' malloc
      // on the maxlength of the session which for some reason some people
      // won't enjoy!
      if (packet.payloadLength() != sizeof(SessionResponseStruct))
      {
          // Either SessionResponseStruct changed or this isn't a session
          // response.
#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
          seqDebug("EQPacket: Ignoring SessionResponse %s:%u->%s:%u with invalid size %d.",
            ((EQUDPIPPacketFormat&) packet).getIPv4SourceA().ascii(),
            ((EQUDPIPPacketFormat&) packet).getSourcePort(),
            ((EQUDPIPPacketFormat&) packet).getIPv4DestA().ascii(),
            ((EQUDPIPPacketFormat&) packet).getDestPort(),
            packet.payloadLength());
#endif
          break;
      }

      // Pull off session response information
      SessionResponseStruct* response = 
        (SessionResponseStruct*) packet.payload();

      m_maxLength = eqntohuint32((uint8_t*)&(response->maxLength));
      m_sessionKey = eqntohuint32((uint8_t*)&(response->key));
      m_sessionId = eqntohuint32((uint8_t*)&(response->sessionId));

      // Sanity check the max length requested
      if (m_maxLength > maxPacketSize)
      {
        seqWarn("EQPacket: SessionResponse wanted a max packet size of %d which is above our sane max packet size of %d. Using our max",
          m_maxLength, maxPacketSize);

        m_maxLength = maxPacketSize;
      }

      emit maxLength((int) m_maxLength, (int) m_streamid);

#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionResponse found %s:%u->%s:%u, resetting expected seq, stream %s (%d) (session tracking %s)",
        ((EQUDPIPPacketFormat&) packet).getIPv4SourceA().ascii(),
        ((EQUDPIPPacketFormat&) packet).getSourcePort(),
        ((EQUDPIPPacketFormat&) packet).getIPv4DestA().ascii(),
        ((EQUDPIPPacketFormat&) packet).getDestPort(),
	    EQStreamStr[m_streamid], m_streamid,
        (m_session_tracking_enabled == 2 ? "locked on" : 
          (m_session_tracking_enabled == 1 ? "enabled" : "disabled")));
#endif
      
#if defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionResponse sessionId %u maxLength %u, key is %u for stream %s (%d)",
        m_sessionId, m_maxLength, m_sessionKey, 
        EQStreamStr[m_streamid], m_streamid);
#endif

#if defined(PACKET_SESSION_DIAG) && (PACKET_SESSION_DIAG > 1)
      seqDebug("EQPacket: SessionResponse contents: sessionId %u, key %u, unknown %u, unknown %u, maxLength %u, unknown %u",
        m_sessionId, m_sessionKey, 
        eqntohuint16((uint8_t*)&(response->unknown0008)),
        response->unknown0010, m_maxLength,
        eqntohuint32((uint8_t*) &(response->unknown0015)));
#endif

#if defined(PACKET_SESSION_DIAG) && (PACKET_SESSION_DIAG > 2)
      seqDebug("EQPacket: Raw SessionResponse: %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x",
        packet.payload()[0], packet.payload()[1], packet.payload()[2], 
        packet.payload()[3], packet.payload()[4], packet.payload()[5], 
        packet.payload()[6], packet.payload()[7], packet.payload()[8], 
        packet.payload()[9], packet.payload()[10], packet.payload()[11],
        packet.payload()[12], packet.payload()[13], packet.payload()[14], 
        packet.payload()[15], packet.payload()[16], packet.payload()[17], 
        packet.payload()[18]);
#endif

      // Provide key to corresponding stream from this session/stream
      emit sessionKey(m_sessionId, m_streamid, m_sessionKey);

      m_arqSeqExp = 0;
      m_arqSeqFound = true;

      // Session tracking
      if (m_session_tracking_enabled)
      {
        // Save off client port for the stream so we can match against it
        // later. SessionRequest should always be an outer protocol packet
        // so we can cast it to EQUDPIPPacketFormat to get the ip headers.
        m_sessionClientPort = ((EQUDPIPPacketFormat&) packet).getDestPort();

        // If this is the world server talking to us, reset session tracking if
        // it is on so we unlatch the client in case of getting kicked.
        if (m_streamid == world2client)
        {
          m_session_tracking_enabled = 1;
          emit sessionTrackingChanged(m_session_tracking_enabled);
        }
        // If this is the zone server talking to us, close the latch and lock
        else if (m_streamid == zone2client)
        {
          // SessionResponse should always be an outer protocol packet, so
          // the EQProtocolPacket passed in can be cast back to
          // EQUDPIPPacketFormat, which we need to go to get access to the IP
          // headers!
          m_session_tracking_enabled = 2;
  
          emit lockOnClient(((EQUDPIPPacketFormat&) packet).getSourcePort(), 
            ((EQUDPIPPacketFormat&) packet).getDestPort());
          emit sessionTrackingChanged(m_session_tracking_enabled);
        }
      }
    }
    break;
    case OP_SessionDisconnect:
    {
#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionDisconnect found %s:%u->%s:%u, resetting expected seq, stream %s (%d) (session tracking %s)",
        ((EQUDPIPPacketFormat&) packet).getIPv4SourceA().ascii(),
        ((EQUDPIPPacketFormat&) packet).getSourcePort(),
        ((EQUDPIPPacketFormat&) packet).getIPv4DestA().ascii(),
        ((EQUDPIPPacketFormat&) packet).getDestPort(),
	    EQStreamStr[m_streamid], m_streamid,
        (m_session_tracking_enabled == 2 ? "locked on" : 
          (m_session_tracking_enabled == 1 ? "enabled" : "disabled")));
#endif

#if defined(PACKET_SESSION_DIAG) && (PACKET_SESSION_DIAG > 2)
      seqDebug("EQPacket: Raw SessionDisconnect: %02x%02x %02x%02x %02x%02x %02x%02x",
        packet.payload()[0], packet.payload()[1], packet.payload()[2], 
        packet.payload()[3], packet.payload()[4], packet.payload()[5], 
        packet.payload()[6], packet.payload()[7]);
#endif

      m_arqSeqExp = 0;

      // Clear cache
      resetCache();

      // Signal closing. Unlatch session tracking if it is on.
      if (m_session_tracking_enabled)
      {
        m_session_tracking_enabled = 1;
        emit sessionTrackingChanged(m_session_tracking_enabled);

        m_sessionClientPort = 0;
      }

      emit closing(m_sessionId, m_streamid);
    }
    break;
    case OP_Ack:
    case OP_AckFuture:
    case OP_AckAfterDisconnect:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: no-op on ACK for net opcode %04x seq %04x, stream %s (%d)",
	    packet.getNetOpCode(), eqntohuint16(packet.payload()), 
        EQStreamStr[m_streamid], m_streamid);
#endif
    }
    break;
    case OP_KeepAlive:
    case OP_SessionStatRequest:
    case OP_SessionStatResponse:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: no-op on stats for net opcode %04x, stream %s (%d)",
	    packet.getNetOpCode(), EQStreamStr[m_streamid], m_streamid);
#endif
    }
    break;
    default :
    {
      seqWarn("EQPacket: Unhandled net opcode %04x, stream %s, size %d",
        packet.getNetOpCode(), EQStreamStr[m_streamid], packet.payloadLength());
    }
  }
}
Exemple #23
0
/////////////////////////////////////////////////////
// Handle a protocol level packet. This could be either a top-level
// EQUDPIPPacket or a subpacket that is just an EQProtocolPacket. Either way
// we use net opcodes here.
void EQPacketStream::processPacket(EQProtocolPacket& packet, bool isSubpacket)
{
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
  seqDebug("-->EQPacketStream::processPacket, subpacket=%s on stream %s (%d)",
    (isSubpacket ? "true" : "false"), EQStreamStr[m_streamid], m_streamid);
#endif

  if (IS_APP_OPCODE(packet.getNetOpCode()))
  {
    // This is an app-opcode directly on the wire with no wrapping protocol
    // information. Weird, but whatever gets the stream read, right?
	dispatchPacket(packet.payload(), packet.payloadLength(), 
        packet.getNetOpCode(), m_opcodeDB.find(packet.getNetOpCode()));
    return;
  }

  // Process the net opcode
  switch (packet.getNetOpCode())
  {
    case OP_Combined:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: found combined packet (net op: %04x, size %d) on stream %s (%d). Unrolling.", 
        packet.getNetOpCode(), packet.payloadLength(),
        EQStreamStr[m_streamid], m_streamid);
#endif

      // Rolled up multiple packets inside this packet. Need to unroll them
      // and process them individually. subpacket starts after the net opcode.
      uint8_t* subpacket = packet.payload();

      while (subpacket < packet.payload() + packet.payloadLength())
      {
        // Length specified first on the wire.
        uint8_t subpacketLength = subpacket[0];

        // Move past the length
        subpacket++;

        // OpCode (in net order)
        uint16_t subOpCode = *(uint16_t*)subpacket;
        
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: unrolling length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif
        
        // Opcode is next. Net opcode or app opcode?
        if (IS_NET_OPCODE(subOpCode))
        {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
          seqDebug("EQPacket: processing unrolled net opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
            subpacketLength, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // Net opcode. false = copy. true = subpacket
          EQProtocolPacket spacket(subpacket, subpacketLength, false, true);

          processPacket(spacket, true);
        }
        else
        {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: processing unrolled app opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength-2, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // App opcode. Dispatch it, skipping opcode.
          dispatchPacket(&subpacket[2], subpacketLength-2, 
            subOpCode, m_opcodeDB.find(subOpCode));
        }
        subpacket += subpacketLength;
      }
    }
    break;
    case OP_AppCombined:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: found appcombined packet (net op: %04x, size %d) on stream %s (%d). Unrolling.", 
        packet.getNetOpCode(), packet.payloadLength(),
        EQStreamStr[m_streamid], m_streamid);
#endif

      // Multiple app op codes in the same packet. Need to unroll and dispatch
      // them.
      uint8_t* subpacket = packet.payload();

      while (subpacket < packet.payload() + packet.payloadLength())
      {
        // Length specified first on the wire.
        uint8_t subpacketLength = subpacket[0];

        // Move past the length
        subpacket++;

        if (subpacketLength != 0xff)
        {
          // Dispatch app op code using given packet length. Net order!
          uint16_t subOpCode = *(uint16_t*)(subpacket);

#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: unrolling length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength, EQStreamStr[m_streamid], m_streamid, subOpCode);
        seqDebug("EQPacket: processing unrolled app opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          subpacketLength-2, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // Dispatch, skipping op code.
          dispatchPacket(&subpacket[2], subpacketLength-2, 
            subOpCode, m_opcodeDB.find(subOpCode));

          // Move ahead
          subpacket += subpacketLength;
        }
        else
        {
          // If original length is 0xff, it means it is a long one. The length
          // is 2 bytes and next.
          uint16_t longOne = eqntohuint16(subpacket);
 
          // Move past the 2 byte length
          subpacket += 2;

          // OpCode next. Net order for op codes.
          uint16_t subOpCode = *(uint16_t*)subpacket;
          
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
        seqDebug("EQPacket: unrolling length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          longOne, EQStreamStr[m_streamid], m_streamid, subOpCode);
        seqDebug("EQPacket: processing unrolled app opcode, length %d bytes from combined packet on stream %s (%d). Opcode %04x", 
          longOne-2, EQStreamStr[m_streamid], m_streamid, subOpCode);
#endif

          // Dispatch, skipping op code.
          dispatchPacket(&subpacket[2], longOne-2, 
            subOpCode, m_opcodeDB.find(subOpCode));

          // Move ahead
          subpacket += longOne;
        }
      }
    }
    break;
    case OP_Packet:
    {
      // Normal unfragmented sequenced packet.
      uint16_t seq = eqntohuint16(packet.payload());
      emit seqReceive(seq, (int)m_streamid);

      if (seq >= m_arqSeqExp)
      {
        // Future packet?
        if (seq == m_arqSeqExp)
        {
          // Expected packet.
          m_arqSeqExp++;
          emit seqExpect(m_arqSeqExp, (int)m_streamid);

          // OpCode next. Net order for op codes.
          uint16_t subOpCode = *(uint16_t*)(&packet.payload()[2]);
       
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
          seqDebug("SEQ: Found next sequence number in data stream %s (%d), incrementing expected seq, %04x (op code %04x, sub opcode %04x)", 
	        EQStreamStr[m_streamid], m_streamid, seq, packet.getNetOpCode(),
            subOpCode);
#endif

          // App opcode or net opcode?
          if (IS_NET_OPCODE(subOpCode))
          {
            // Net opcode. false = no copy. true = subpacket.
            EQProtocolPacket spacket(&packet.payload()[2],
              packet.payloadLength()-2, false, true);

            processPacket(spacket, true);
          }
          else
          {
            // App opcode. Dispatch, skipping seq and opcode.
            dispatchPacket(&packet.payload()[4], packet.payloadLength()-4,
              subOpCode, m_opcodeDB.find(subOpCode));
          }
        }
        else if (seq < (uint32_t(m_arqSeqExp + arqSeqWrapCutoff)) ||
                 seq < (int32_t(m_arqSeqExp - arqSeqWrapCutoff)))
        {
          // Yeah, future packet. Push it on the packet cache.
#ifdef PACKET_PROCESS_DIAG
          seqDebug("SEQ: out of order sequence %04x stream %s (%d) expecting %04x, sending to cache, %04d",
	        seq, EQStreamStr[m_streamid], m_streamid, 
            m_arqSeqExp, m_cache.size());
#endif
          setCache(seq, packet);
        }
        else
        {
          // Past packet outside the cut off
          seqWarn("SEQ: received sequenced %spacket outside the bounds of reasonableness. Expecting seq=%04x got seq=%04x, reasonableness being %d in the future.", 
            (isSubpacket ? "sub" : ""), m_arqSeqExp, seq, arqSeqWrapCutoff);
        }
      }
      else
      {
        // Spooky packet from the past. Boo!
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
        seqDebug("discarding %spacket netopcode=%04x seq=%d size=%d on stream %s (%d). Packet is in the past. We've moved on.",
          (isSubpacket ? "sub" : ""),
          packet.getNetOpCode(), seq, packet.payloadLength(),
          EQStreamStr[m_streamid], m_streamid);
#endif
      }
    }
    break;
    case OP_Oversized:
    {
      // Fragmented sequenced data packet.
      uint16_t seq = eqntohuint16(packet.payload());
      emit seqReceive(seq, (int)m_streamid);

      if (seq >= m_arqSeqExp)
      {
        // Future packet?
        if (seq > m_arqSeqExp)
        {
          // Yeah, future packet. Push it on the packet cache.
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
          seqDebug("SEQ: out of order sequence %04x stream %s (%d) expecting %04x, sending to cache, %04d",
	        seq, EQStreamStr[m_streamid], m_streamid, 
            m_arqSeqExp, m_cache.size());
#endif
          setCache(seq, packet);
        }
        else
        {
          // Expected packet.
          m_arqSeqExp++;
          emit seqExpect(m_arqSeqExp, (int)m_streamid);
       
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
          seqDebug("SEQ: Found next sequence number in data stream %s (%d), incrementing expected seq, %04x (op code %04x)", 
	        EQStreamStr[m_streamid], m_streamid, seq, packet.getNetOpCode());
#endif

          // Push the fragment on.
          m_fragment.addFragment(packet);

          if (m_fragment.isComplete())
          {
            // OpCode from fragment. In network order.
            uint16_t fragOpCode = *(uint16_t*)(m_fragment.data());

#ifdef PACKET_PROCESS_DIAG
          seqDebug("SEQ: Completed oversized app packet on stream %s with seq %04x, total size %d opcode %04x", 
	        EQStreamStr[m_streamid], seq, m_fragment.size()-2, fragOpCode);
#endif

            // dispatch fragment. Skip opcode.
            dispatchPacket(&m_fragment.data()[2], m_fragment.size()-2,
              fragOpCode, m_opcodeDB.find(fragOpCode)); 

            m_fragment.reset();
          }
        }
      }
      else
      {
        // Spooky packet from the past. Boo!
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)
        seqDebug("discarding packet netopcode=%04x seq=%d size=%d on stream %s (%d). Packet is in the past. We've moved on.",
          packet.getNetOpCode(), seq, packet.payloadLength(),
          EQStreamStr[m_streamid], m_streamid);
#endif
      }
    }
    break;
    case OP_SessionRequest:
    {
      // Session request from client to server.
#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionRequest found, resetting expected seq, stream %s (%d) (session tracking %s)",
	    EQStreamStr[m_streamid], m_streamid,
        (m_session_tracking_enabled == 2 ? "locked on" : 
          (m_session_tracking_enabled == 1 ? "enabled" : "disabled")));
#endif
      
      // Pull off session request information
      SessionRequestStruct* request = 
        (SessionRequestStruct*) packet.payload();

      m_sessionId = eqntohuint32((uint8_t*)&(request->sessionId));
      m_maxLength = eqntohuint32((uint8_t*)&(request->maxLength));

#if defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionRequest sessionId %u maxLength %u, awaiting key for stream %s (%d)",
        m_sessionId,
        m_maxLength,
        EQStreamStr[m_streamid],
        m_streamid);
#endif

#if defined(PACKET_SESSION_DIAG) && (PACKET_SESSION_DIAG > 1)
      seqDebug("EQPacket: SessionRequest contents: unknown %u, sessionId %u, maxLength %u",
        eqntohuint32((uint8_t*)&(request->unknown0000)),
        m_sessionId,
        m_maxLength);
#endif

      m_arqSeqExp = 0;
      m_arqSeqFound = true;
    }
    break;
    case OP_SessionResponse:
    {
      // Session response from server
#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionResponse found, resetting expected seq, stream %s (%d) (session tracking %s)",
	    EQStreamStr[m_streamid], m_streamid,
        (m_session_tracking_enabled == 2 ? "locked on" : 
          (m_session_tracking_enabled == 1 ? "enabled" : "disabled")));
#endif
      
      // Pull off session response information
      SessionResponseStruct* response = 
        (SessionResponseStruct*) packet.payload();

      m_maxLength = eqntohuint32((uint8_t*)&(response->maxLength));
      m_sessionKey = eqntohuint32((uint8_t*)&(response->key));
      m_sessionId = eqntohuint32((uint8_t*)&(response->sessionId));

#if defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionResponse sessionId %u maxLength %u, key is %u for stream %s (%d)",
        m_sessionId,
        m_maxLength,
        m_sessionKey,
        EQStreamStr[m_streamid],
        m_streamid);
#endif

#if defined(PACKET_SESSION_DIAG) && (PACKET_SESSION_DIAG > 1)
      seqDebug("EQPacket: SessionResponse contents: sessionId %u, key %u, unknown %u, unknown %u, maxLength %u, unknown %u",
        m_sessionId,
        m_sessionKey,
        eqntohuint16((uint8_t*)&(response->unknown0008)),
        response->unknown0010,
        m_maxLength,
        eqntohuint32((uint8_t*) &(response->unknown0015)));
#endif

      // Provide key to corresponding stream from this session/stream
      emit sessionKey(m_sessionId, m_streamid, m_sessionKey);

      m_arqSeqExp = 0;
      m_arqSeqFound = true;

      // Session tracking
      if (m_session_tracking_enabled)
      {
        // If this is the world server talking to us, reset session tracking if
        // it is on so we unlatch the client in case of getting kicked.
        if (m_streamid == world2client)
        {
          m_session_tracking_enabled = 1;
          emit sessionTrackingChanged(m_session_tracking_enabled);
        }
        // If this is the zone server talking to us, close the latch and lock
        else if (m_streamid == zone2client)
        {
          // SessionResponse should always be an outer protocol packet, so
          // the EQProtocolPacket passed in can be cast back to
          // EQUDPIPPacketFormat, which we need to go to get access to the IP
          // headers!
          m_session_tracking_enabled = 2;
  
          emit lockOnClient(((EQUDPIPPacketFormat&) packet).getSourcePort(), 
            ((EQUDPIPPacketFormat&) packet).getDestPort());
          emit sessionTrackingChanged(m_session_tracking_enabled);
        }
      }
    }
    break;
    case OP_SessionDisconnect:
    {
#if defined(PACKET_PROCESS_DIAG) || defined(PACKET_SESSION_DIAG)
      seqDebug("EQPacket: SessionDisconnect found, resetting expected seq, stream %s (%d) (session tracking %s)",
	    EQStreamStr[m_streamid], m_streamid,
        (m_session_tracking_enabled == 2 ? "locked on" : 
          (m_session_tracking_enabled == 1 ? "enabled" : "disabled")));
#endif

      m_arqSeqExp = 0;

      // Clear cache
      resetCache();

      // Signal closing. Unlatch session tracking if it is on.
      if (m_session_tracking_enabled)
      {
        m_session_tracking_enabled = 1;
        emit sessionTrackingChanged(m_session_tracking_enabled);
      }

      emit closing();
    }
    break;
    case OP_Ack:
    case OP_Resend:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: no-op on for net opcode %04x seq %04x, stream %s (%d)",
	    packet.getNetOpCode(), eqntohuint16(packet.payload()),
        EQStreamStr[m_streamid], m_streamid);
#endif
    }
    break;
    case OP_KeepAlive:
    case OP_SessionStatRequest:
    case OP_SessionStatResponse:
    {
#if defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 2)
      seqDebug("EQPacket: no-op on for net opcode %04x, stream %s (%d)",
	    packet.getNetOpCode(), EQStreamStr[m_streamid], m_streamid);
#endif
    }
    break;
    default :
    {
      seqWarn("EQPacket: Unhandled net opcode %04x, stream %s, size %d",
        packet.getNetOpCode(), EQStreamStr[m_streamid], packet.payloadLength());
    }
  }
}