Logo Search packages:      
Sourcecode: kmess version File versions

bool P2PApplicationBase::sendNextDataParts ( int  preferredFragments  )  [inherited]

Called when the connection is ready to send more file data.

Parameters:
preferredFragments The preferred number of fragments to send at once.
The sendData() method calls ApplicationList::registerDataSendingApplication() to start this notification process. Each time the direct connection is ready to send more data, ApplicationList::slotConnectionReadyWrite() is called which calls this method.

Returns:
Returns false if something failed, and this method should not be called again.

Definition at line 1356 of file p2papplicationbase.cpp.

References Application::CANCEL_FAILED, Application::getContactHandle(), Application::isClosing(), P2PMessage::MSN_FLAG_OBJECT_DATA, P2PApplicationBase::P2P_MSG_DATA, P2PApplicationBase::P2P_TYPE_FILE, P2PApplicationBase::P2P_TYPE_NEGOTIATION, P2PApplicationBase::P2P_TYPE_PICTURE, P2PApplicationBase::P2P_WAIT_FOR_DATA_ACK, Application::sendCancelMessage(), P2PApplicationBase::sendP2PMessageImpl(), P2PApplicationBase::setWaitingState(), Application::showTransferProgress(), and ApplicationList::unregisterDataSendingApplication().

Referenced by ApplicationList::slotConnectionReadyWrite(), and ApplicationList::slotSwitchboardTestReadyWrite().

{
  // Abort if the data sending was reset.
  // Also fixes race conditions with signals.
  if( dataType_ == P2P_TYPE_NEGOTIATION || isClosing() || KMESS_NULL(dataSource_) )
  {
#ifdef KMESSDEBUG_P2PAPPLICATION_GENERAL
    kDebug() << "called while aborting "
                "(datatype=" << dataType_ <<
                " isclosing=" << isClosing() <<
                " userAborted=" << userAborted_ <<  // sort-of reserved for aborts from ApplicationList.
                " datasource=" << dataSource_ <<
                " waitingState=" << waitingState_ <<
                " contact=" << getContactHandle() << ").";
#endif

    // Request caller not to call us again.
    return false;
  }


  // Allow the caller to specify the number of loops,
  // e.g. more for a direct connection, less for parallel transfers.
  int loops = qMax( preferredFragments, 1 );
  while( --loops >= 0 && fragmentOffset_ < fragmentTotalSize_ && dataSource_ != 0 && ! dataSource_->atEnd() )
  {
    // Read the data from the file.
    char buffer[1202]; // 1202 is the max P2P data size.
    qint64 bytesRead = dataSource_->read( buffer, 1202 );
    if( bytesRead < 0 )
    {
      kWarning() << "Couldn't send more data, "
                    "read error at " << fragmentOffset_ << " of " << fragmentTotalSize_ << " bytes "
                    "(contact=" << getContactHandle() <<
                    " session=" << getSessionID() <<
                    " class="   << metaObject()->className() <<
                    " action=slpcancel).";
      sendCancelMessage( CANCEL_FAILED );
      return ( dataSource_ == 0 );  // return true if already aborted by sendCancelMessage().
    }
    else if( bytesRead == 0 )
    {
      break;
    }

    // Wrap in buffer, without copying.
    QByteArray data = QByteArray::fromRawData( buffer, (int)bytesRead );

#ifdef KMESSDEBUG_P2PAPPLICATION_GENERAL
    kDebug() << "Sending data:"
              << " offset=" << fragmentOffset_
              << " buffer=" << bytesRead;
#endif

    // Determine the progress value now because mesageOffset_ it reset by the last sendP2PMessageImpl() call.
    unsigned long nextProgressValue = ( fragmentOffset_ + (quint32)bytesRead );

    // Determine the flags:
    // Funny, MSN6 doesn't seam to care which flag was set
    // while transferring the file. KMess however, does.
    uint flag = 0;
    switch( dataType_ )
    {
      case P2P_TYPE_PICTURE: flag = P2PMessage::MSN_FLAG_OBJECT_DATA; break;
      case P2P_TYPE_FILE:    flag = P2PMessage::MSN_FLAG_FILE_DATA;   break;
      default:
        // Display error message for the first message only.
        if( fragmentOffset_ == 0 )
        {
          kWarning() << "Unknown data transfer mode "
                        "(mode=" << dataType_ <<
                        " contact=" << getContactHandle() <<
                        " session=" << getSessionID() <<
                        " class="   << metaObject()->className() <<
                        " action=tryflag).";
        }
    }

    // Send the message
    bool writeSuccess = sendP2PMessageImpl( data, flag, dataType_, P2P_MSG_DATA, fragmentMessageID_ );

    // Avoid next round if write was blocked already.
    // This could happen if a direct connection can't write all data.
    // The DirectConnectionBase class will automatically send the remaining parts, so don't worry about that here.
    if( ! writeSuccess )
    {
#ifdef KMESSDEBUG_P2PAPPLICATION_GENERAL
      kDebug() << "message could not be written entirely, leaving loop early.";
#endif
      break;
    }

    // Dispatch the progress to the derived class
    showTransferProgress( nextProgressValue );
  }


  // Rounds completed, make final assertions.
  // Be verbose if something internally goes wrong.
  if( dataSource_ != 0 && dataSource_->atEnd() && fragmentOffset_ < fragmentTotalSize_ )
  {
    kWarning() << "data source is at the end, "
                  "but offset byte count is not "
                  "(fragmentoffset="    << fragmentOffset_ <<
                  " fragmenttotalsize=" << fragmentTotalSize_ <<
                  " sourceopen="        << dataSource_->isOpen() <<
                  " sourcesize="        << dataSource_->size() <<
                  " datatype="          << dataType_ <<
                  " contact="           << getContactHandle() <<
                  " session="           << getSessionID() <<
                  " class="             << metaObject()->className() <<
                  " action=resetstate)!";

    // Reset for next p2p message.
    fragmentTotalSize_ = 0;
    fragmentOffset_    = 0;
  }

  // See if transfer completed,
  // if so tell the application list to stop calling this method.
  if( fragmentOffset_ == 0 || fragmentOffset_ >= fragmentTotalSize_ )
  {
    dataSource_ = 0;
    dataType_   = P2P_TYPE_NEGOTIATION;
    applicationList_->unregisterDataSendingApplication( this );

#ifdef KMESSDEBUG_P2PAPPLICATION_GENERAL
    kDebug() << "Waiting for all data received ACK...";
#endif

    // Now wait for the contact to ACK that it received all data.
    setWaitingState( P2P_WAIT_FOR_DATA_ACK, P2PAPPLICATION_TIMEOUT_ACK );

    // no return false, will unregister the app twice.
  }

  return true;
}


Generated by  Doxygen 1.6.0   Back to index