void transferThread::send(const QString &filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { qCritical("Could not open the file."); return; } emit sendLock(true); this->m_stop = false; quint32 step_size = 116; const quint32 from = 0; const quint32 to = file.size(); quint32 progress, oldprogress; qint32 read; char *buf2 = new char[step_size]; qDebug() << "File size" << file.size(); if (!this->m_btl->eraseFlash(file.size())) { emit sendStatus("Erase failed"); emit sendLog("Erase failed"); qDebug() << "Erase failed"; emit sendLock(false); return; } else { emit sendStatus("Erase OK"); emit sendLog("Erase OK"); qDebug() << "Erase OK"; } qInformal() << "Writing from" << "0x"+QString::number(from, 16) << "to" << "0x"+QString::number(to, 16); emit sendStatus("Transfering"); emit sendLog("Transfering"); progress = 0; for (int i=0; i<=file.size(); i+=step_size) { if (this->m_stop) break; if (file.atEnd()) { qDebug() << "End Of File"; break; } memset(buf2, 0, step_size); if ((read = file.read(buf2, step_size)) <= 0) break; qDebug() << "Read" << read << "Bytes from disk"; QByteArray buf(buf2, read); if (this->m_btl->writeFlash(i, &buf, step_size) < read){ emit sendStatus("Transfer failed"); emit sendLog("Transfer failed"); break; } oldprogress = progress; progress = (i*100)/file.size(); if (progress > oldprogress) { // Push only if number has increased emit sendProgress(progress); qInformal() << "Progress:"<< QString::number(progress)+"%"; } } emit sendLoaderStatus("Idle"); file.close(); delete buf2; emit sendProgress(100); emit sendStatus("Transfer done"); emit sendLog("Transfer done"); qInformal() << "Transfer done"; emit sendLock(false); }
/** * The thread method that handles calling send for the individual sockets. * * Control packets will always be tried to be sent first. If there is any bandwidth leftover * after that, send() for the upload slot sockets will be called in priority order until we have run * out of available bandwidth for this loop. Upload slots will not be allowed to go without having sent * called for more than a defined amount of time (i.e. two seconds). * * @return always returns 0. */ void* UploadBandwidthThrottler::Entry() { const uint32 TIME_BETWEEN_UPLOAD_LOOPS = 1; uint32 lastLoopTick = GetTickCountFullRes(); // Bytes to spend in current cycle. If we spend more this becomes negative and causes a wait next time. sint32 bytesToSpend = 0; uint32 allowedDataRate = 0; uint32 rememberedSlotCounter = 0; uint32 extraSleepTime = TIME_BETWEEN_UPLOAD_LOOPS; while (m_doRun && !TestDestroy()) { uint32 timeSinceLastLoop = GetTickCountFullRes() - lastLoopTick; // Calculate data rate if (thePrefs::GetMaxUpload() == UNLIMITED) { // Try to increase the upload rate from UploadSpeedSense allowedDataRate = (uint32)theStats::GetUploadRate() + 5 * 1024; } else { allowedDataRate = thePrefs::GetMaxUpload() * 1024; } uint32 minFragSize = 1300; uint32 doubleSendSize = minFragSize*2; // send two packages at a time so they can share an ACK if (allowedDataRate < 6*1024) { minFragSize = 536; doubleSendSize = minFragSize; // don't send two packages at a time at very low speeds to give them a smoother load } uint32 sleepTime; if (bytesToSpend < 1) { // We have sent more than allowed in last cycle so we have to wait now // until we can send at least 1 byte. sleepTime = std::max((-bytesToSpend + 1) * 1000 / allowedDataRate + 2, // add 2 ms to allow for rounding inaccuracies extraSleepTime); } else { // We could send at once, but sleep a while to not suck up all cpu sleepTime = extraSleepTime; } if (timeSinceLastLoop < sleepTime) { Sleep(sleepTime-timeSinceLastLoop); } // Check after sleep in case the thread has been signaled to end if (!m_doRun || TestDestroy()) { break; } const uint32 thisLoopTick = GetTickCountFullRes(); timeSinceLastLoop = thisLoopTick - lastLoopTick; lastLoopTick = thisLoopTick; if (timeSinceLastLoop > sleepTime + 2000) { AddDebugLogLineN(logGeneral, CFormat(wxT("UploadBandwidthThrottler: Time since last loop too long. time: %ims wanted: %ims Max: %ims")) % timeSinceLastLoop % sleepTime % (sleepTime + 2000)); timeSinceLastLoop = sleepTime + 2000; } // Calculate how many bytes we can spend bytesToSpend += (sint32) (allowedDataRate / 1000.0 * timeSinceLastLoop); if (bytesToSpend >= 1) { sint32 spentBytes = 0; sint32 spentOverhead = 0; wxMutexLocker sendLock(m_sendLocker); { wxMutexLocker queueLock(m_tempQueueLocker); // are there any sockets in m_TempControlQueue_list? Move them to normal m_ControlQueue_list; m_ControlQueueFirst_list.insert( m_ControlQueueFirst_list.end(), m_TempControlQueueFirst_list.begin(), m_TempControlQueueFirst_list.end() ); m_ControlQueue_list.insert( m_ControlQueue_list.end(), m_TempControlQueue_list.begin(), m_TempControlQueue_list.end() ); m_TempControlQueue_list.clear(); m_TempControlQueueFirst_list.clear(); } // Send any queued up control packets first while (spentBytes < bytesToSpend && (!m_ControlQueueFirst_list.empty() || !m_ControlQueue_list.empty())) { ThrottledControlSocket* socket = NULL; if (!m_ControlQueueFirst_list.empty()) { socket = m_ControlQueueFirst_list.front(); m_ControlQueueFirst_list.pop_front(); } else if (!m_ControlQueue_list.empty()) { socket = m_ControlQueue_list.front(); m_ControlQueue_list.pop_front(); } if (socket != NULL) { SocketSentBytes socketSentBytes = socket->SendControlData(bytesToSpend-spentBytes, minFragSize); spentBytes += socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets; spentOverhead += socketSentBytes.sentBytesControlPackets; } } // Check if any sockets haven't gotten data for a long time. Then trickle them a package. uint32 slots = m_StandardOrder_list.size(); for (uint32 slotCounter = 0; slotCounter < slots; slotCounter++) { ThrottledFileSocket* socket = m_StandardOrder_list[ slotCounter ]; if (socket != NULL) { if (thisLoopTick-socket->GetLastCalledSend() > SEC2MS(1)) { // trickle uint32 neededBytes = socket->GetNeededBytes(); if (neededBytes > 0) { SocketSentBytes socketSentBytes = socket->SendFileAndControlData(neededBytes, minFragSize); spentBytes += socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets; spentOverhead += socketSentBytes.sentBytesControlPackets; } } } else { AddDebugLogLineN(logGeneral, CFormat( wxT("There was a NULL socket in the UploadBandwidthThrottler Standard list (trickle)! Prevented usage. Index: %i Size: %i")) % slotCounter % m_StandardOrder_list.size()); } } // Give available bandwidth to slots, starting with the one we ended with last time. // There are two passes. First pass gives packets of doubleSendSize, second pass // gives as much as possible. // Second pass starts with the last slot of the first pass actually. for (uint32 slotCounter = 0; (slotCounter < slots * 2) && spentBytes < bytesToSpend; slotCounter++) { if (rememberedSlotCounter >= slots) { // wrap around pointer rememberedSlotCounter = 0; } uint32 data = (slotCounter < slots - 1) ? doubleSendSize // pass 1 : (bytesToSpend - spentBytes); // pass 2 ThrottledFileSocket* socket = m_StandardOrder_list[ rememberedSlotCounter ]; if (socket != NULL) { SocketSentBytes socketSentBytes = socket->SendFileAndControlData(data, doubleSendSize); spentBytes += socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets; spentOverhead += socketSentBytes.sentBytesControlPackets; } else { AddDebugLogLineN(logGeneral, CFormat(wxT("There was a NULL socket in the UploadBandwidthThrottler Standard list (equal-for-all)! Prevented usage. Index: %i Size: %i")) % rememberedSlotCounter % m_StandardOrder_list.size()); } rememberedSlotCounter++; } // Do some limiting of what we keep for the next loop. bytesToSpend -= spentBytes; sint32 minBytesToSpend = (slots + 1) * minFragSize; if (bytesToSpend < - minBytesToSpend) { bytesToSpend = - minBytesToSpend; } else { sint32 bandwidthSavedTolerance = slots * 512 + 1; if (bytesToSpend > bandwidthSavedTolerance) { bytesToSpend = bandwidthSavedTolerance; } } m_SentBytesSinceLastCall += spentBytes; m_SentBytesSinceLastCallOverhead += spentOverhead; if (spentBytes == 0) { // spentBytes includes the overhead extraSleepTime = std::min<uint32>(extraSleepTime * 5, 1000); // 1s at most } else { extraSleepTime = TIME_BETWEEN_UPLOAD_LOOPS; } } } { wxMutexLocker queueLock(m_tempQueueLocker); m_TempControlQueue_list.clear(); m_TempControlQueueFirst_list.clear(); } wxMutexLocker sendLock(m_sendLocker); m_ControlQueue_list.clear(); m_StandardOrder_list.clear(); return 0; }
void transferThread::verify(const QString &filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { qCritical("Could not open the file."); return; } emit sendLock(true); this->m_stop = false; const quint32 buf_size = 512; const quint32 from = 0; const quint32 to = file.size(); qInformal() << "Reading from" << QString::number(from, 16) << "to" << QString::number(to, 16); quint32 addr, progress, oldprogress; QByteArray data_local, data_remote; progress = 0; for (quint32 i=0; i<file.size(); i+=buf_size) { if (this->m_stop) break; usleep(50000); data_local = file.read(buf_size); qDebug() << "Read" << data_local.size() << "Bytes from disk"; addr = i; if (!data_local.size()) break; int read_size = this->m_btl->readMem(addr, &data_remote, data_local.size()); if (read_size < data_local.size()) {// Read same amount of data as from file. file.close(); emit sendProgress(0); emit sendStatus("Verification Failed"); qInformal() << "Verification Failed"; qInformal() << "read" << read_size << "valid" << data_local.size(); emit sendLock(false); return; } if (data_remote != data_local) { file.close(); emit sendProgress(100); emit sendStatus("Verification failed at 0x"+QString::number(addr, 16)); QString stmp, sbuf; for (int b=0;b<data_local.size();b++) { stmp.append(QString().sprintf("%02X ", (uchar)data_local.at(b))); sbuf.append(QString().sprintf("%02X ", (uchar)data_remote.at(b))); } qCritical() << "Verification failed at 0x"+QString::number(addr, 16) << "\r\n Expecting:" << stmp << "\r\n Got:" << sbuf; emit sendLock(false); return; } oldprogress = progress; progress = (i*100)/file.size(); if (progress > oldprogress) { // Push only if number has increased emit sendProgress(progress); qInformal() << "Progress:"<< QString::number(progress)+"%"; } emit sendStatus("Verified "+QString::number(i/1024)+" kilobytes out of "+QString::number(file.size()/1024)); } file.close(); emit sendProgress(100); emit sendStatus("Verification OK"); qInformal() << "Verification OK"; emit sendLock(false); }