// FIXME: need to be checked bool InputProtocolBase::safeReadBytes( QCString & data, uint & len ) { // read the length of the bytes Q_UINT32 val; if ( !okToProceed() ) return false; *m_din >> val; m_bytes += sizeof( Q_UINT32 ); if ( val > 1024 ) return false; //qDebug( "EventProtocol::safeReadBytes() - expecting %i bytes", val ); QCString temp( val ); if ( val != 0 ) { if ( !okToProceed() ) return false; // if the server splits packets here we are in trouble, // as there is no way to see how much data was actually read m_din->readRawBytes( temp.data(), val ); // the rest of the string will be filled with FF, // so look for that in the last position instead of \0 // this caused a crash - guessing that temp.length() is set to the number of bytes actually read... // if ( (quint8)( * ( temp.data() + ( temp.length() - 1 ) ) ) == 0xFF ) if ( temp.length() < static_cast<int>( val - 1 ) ) { qDebug( "InputProtocol::safeReadBytes() - string broke, giving up, only got: %i bytes out of %i", temp.length(), val ); m_state = NeedMore; return false; } } data = temp; len = val; m_bytes += val; return true; }
bool ResponseProtocol::readFields( int fieldCount, Field::FieldList * list ) { // build a list of fields. // If there is already a list of fields stored in m_collatingFields, // the list we're reading on this iteration must be a nested list // so when we're done reading it, add it to the MultiList element // that is the last element in the top list in m_collatingFields. // if we find the beginning of a new nested list, push the current list onto m_collatingFields debug( "ResponseProtocol::readFields()" ); if ( fieldCount > 0 ) debug( QString( "reading %1 fields" ).arg( fieldCount ) ); Field::FieldList currentList; while ( fieldCount != 0 ) // prevents bad input data from ruining our day { // the field being read // read field Q_UINT8 type, method; Q_UINT32 val; QCString tag; // read uint8 type if ( !okToProceed() ) { currentList.purge(); return false; } m_din >> type; m_bytes += sizeof( Q_UINT8 ); // if type is 0 SOMETHING_INVALID, we're at the end of the fields if ( type == 0 ) /*&& m_din->atEnd() )*/ { debug( "- end of field list" ); m_packetState = FieldsRead; // do something to indicate we're done break; } // read uint8 method if ( !okToProceed() ) { currentList.purge(); return false; } m_din >> method; m_bytes += sizeof( Q_UINT8 ); // read tag and length if ( !safeReadBytes( tag, val ) ) { currentList.purge(); return false; } debug( QString( "- type: %1, method: %2, tag: %3," ).arg( type ).arg( method ).arg( tag.data() ) ); // if multivalue or array if ( type == NMFIELD_TYPE_MV || type == NMFIELD_TYPE_ARRAY ) { // read length uint32 if ( !okToProceed() ) { currentList.purge(); return false; } m_din >> val; m_bytes += sizeof( Q_UINT32 ); // create multifield debug( QString( " multi field containing: %1" ).arg( val ) ); Field::MultiField* m = new Field::MultiField( tag, method, 0, type ); currentList.append( m ); if ( !readFields( val, ¤tList) ) { currentList.purge(); return false; } } else { if ( type == NMFIELD_TYPE_UTF8 || type == NMFIELD_TYPE_DN ) { QCString rawData; if( !safeReadBytes( rawData, val ) ) { currentList.purge(); return false; } if ( val > NMFIELD_MAX_STR_LENGTH ) { m_packetState = ProtocolError; break; } // convert to unicode - ignore the terminating NUL, because Qt<3.3.2 doesn't sanity check val. QString fieldValue = QString::fromUtf8( rawData.data(), val - 1 ); debug( QString( "- utf/dn single field: %1" ).arg( fieldValue ) ); // create singlefield Field::SingleField* s = new Field::SingleField( tag, method, 0, type, fieldValue ); currentList.append( s ); } else { // otherwise ( numeric ) // read value uint32 if ( !okToProceed() ) { currentList.purge(); return false; } m_din >> val; m_bytes += sizeof( Q_UINT32 ); debug( QString( "- numeric field: %1" ).arg( val ) ); Field::SingleField* s = new Field::SingleField( tag, method, 0, type, val ); currentList.append( s ); } } // decrease the fieldCount if we're using it if ( fieldCount > 0 ) fieldCount--; }
int CoreProtocol::wireToTransfer( const QByteArray& wire ) { kDebug(YAHOO_RAW_DEBUG) ; // processing incoming data and reassembling it into transfers // may be an event or a response uint bytesParsed = 0; if ( wire.size() < 20 ) // minimal value of a YMSG header { m_state = NeedMore; return bytesParsed; } QByteArray tempWire = wire; QDataStream din( &tempWire, QIODevice::ReadOnly ); // look at first four bytes and decide what to do with the chunk if ( okToProceed( din ) ) { if ( (wire[0] == 'Y') && (wire[1] == 'M') && (wire[2] == 'S') && (wire[3] == 'G')) { // kDebug(YAHOO_RAW_DEBUG) << " - looks like a valid YMSG packet"; YMSGTransfer *t = static_cast<YMSGTransfer *>(m_YMSGProtocol->parse( wire, bytesParsed )); // kDebug(YAHOO_RAW_DEBUG) << " - YMSG Protocol parsed " << bytesParsed << " bytes"; if ( t ) { if( wire.size() < t->packetLength() ) { m_state = NeedMore; delete t; return 0; } m_inTransfer = t; // kDebug(YAHOO_RAW_DEBUG) << " - got a valid packet "; m_state = Available; emit incomingData(); } else bytesParsed = 0; } else { kDebug(YAHOO_RAW_DEBUG) << " - not a valid YMSG packet. Trying to recover."; QTextStream s( wire, QIODevice::ReadOnly ); QString remaining = s.readAll(); int pos = remaining.indexOf( "YMSG", bytesParsed ); if( pos >= 0 ) { kDebug(YAHOO_RAW_DEBUG) << "Recover successful."; bytesParsed += pos; } else { kDebug(YAHOO_RAW_DEBUG) << "Recover failed. Dump it!"; bytesParsed = wire.size(); } } } return bytesParsed; }