void BufferedSocket::threadSendFile(InputStream* file) throw(Exception) { dcassert(sock); if(!sock) return; dcassert(file != NULL); size_t sockSize = (size_t)sock->getSocketOptInt(SO_SNDBUF); size_t bufSize = max(sockSize, (size_t)64*1024); vector<uint8_t> readBuf(bufSize); vector<uint8_t> writeBuf(bufSize); size_t readPos = 0; bool readDone = false; dcdebug("Starting threadSend\n"); UploadManager *um = UploadManager::getInstance(); size_t sendMaximum; uint64_t start = 0; bool throttling; while(true) { if(disconnecting) return; throttling = (BOOLSETTING(THROTTLE_ENABLE) && getSuperUser() == false); int UserSleep = getSleep(); // !SMT!-S if(!readDone && readBuf.size() > readPos) { // Fill read buffer size_t bytesRead = readBuf.size() - readPos; // !SMT!-S if (UserSleep >= 0) { // throttleGetSlice() should not be called for superusers, so their downloaded bytes don't count in mUploadLimit if(throttling) { start = GET_TICK(); sendMaximum = um->throttleGetSlice(); if (sendMaximum == (size_t)-1) { throttling = false; sendMaximum = bytesRead; } bytesRead = min(bytesRead, sendMaximum); } if (UserSleep) { ::Sleep(UserSleep); bytesRead = min(bytesRead, (size_t)1024); } // !SMT!-S } size_t actual = file->read(&readBuf[readPos], bytesRead); if(bytesRead > 0) { fire(BufferedSocketListener::BytesSent(), bytesRead, 0); } if(actual == 0) { readDone = true; } else { readPos += actual; } } if(readDone && readPos == 0) { fire(BufferedSocketListener::TransmitDone()); return; } readBuf.swap(writeBuf); readBuf.resize(bufSize); writeBuf.resize(readPos); readPos = 0; size_t writePos = 0; while(writePos < writeBuf.size()) { if(disconnecting) return; size_t writeSize = min(sockSize / 2, writeBuf.size() - writePos); int written = sock->write(&writeBuf[writePos], writeSize); if(written > 0) { writePos += written; fire(BufferedSocketListener::BytesSent(), 0, written); } else if(written == -1) { if(!readDone && readPos < readBuf.size() && UserSleep <= 0) { // !SMT!-S // Read a little since we're blocking anyway... size_t bytesRead = min(readBuf.size() - readPos, readBuf.size() / 2); if(throttling) { start = GET_TICK(); sendMaximum = um->throttleGetSlice(); if (sendMaximum == (size_t)-1) { throttling = false; sendMaximum = bytesRead; } bytesRead = (uint32_t)min((int64_t)bytesRead, (int64_t)sendMaximum); } size_t actual = file->read(&readBuf[readPos], bytesRead); if(bytesRead > 0) { fire(BufferedSocketListener::BytesSent(), bytesRead, 0); } if(actual == 0) { readDone = true; } else { readPos += actual; } } else { while(!disconnecting) { int w = sock->wait(POLL_TIMEOUT, Socket::WAIT_WRITE | Socket::WAIT_READ); if(w & Socket::WAIT_READ) { threadRead(); } if(w & Socket::WAIT_WRITE) { break; } } } } if(throttling) { uint32_t cycle_time = um->throttleCycleTime(); uint64_t sleep_time = cycle_time - (GET_TICK() - start); if (sleep_time > 0 && sleep_time <= cycle_time) { Thread::sleep(sleep_time); } } } Thread::yield(); } }
void BufferedSocket::threadSendFile(InputStream* file) throw(Exception) { if(state != RUNNING) return; if(disconnecting) return; dcassert(file != NULL); size_t sockSize = (size_t)sock->getSocketOptInt(SO_SNDBUF); size_t bufSize = max(sockSize, (size_t)64*1024); ByteVector readBuf(bufSize); ByteVector writeBuf(bufSize); size_t readPos = 0; bool readDone = false; dcdebug("Starting threadSend\n"); UploadManager *um = UploadManager::getInstance(); size_t sendMaximum, start = 0, current= 0; bool throttling; while(true) { if(!readDone && readBuf.size() > readPos) { // Fill read buffer size_t bytesRead = readBuf.size() - readPos; size_t actual = file->read(&readBuf[readPos], bytesRead); if(bytesRead > 0) { fire(BufferedSocketListener::BytesSent(), bytesRead, 0); } if(actual == 0) { readDone = true; } else { readPos += actual; } } if(readDone && readPos == 0) { fire(BufferedSocketListener::TransmitDone()); return; } readBuf.swap(writeBuf); readBuf.resize(bufSize); writeBuf.resize(readPos); readPos = 0; size_t writePos = 0; while(writePos < writeBuf.size()) { if(disconnecting) return; throttling = BOOLSETTING(THROTTLE_ENABLE); size_t writeSize; if(throttling) { start = TimerManager::getTick(); sendMaximum = um->throttleGetSlice(); if(sendMaximum < 0) { throttling = false; writeSize = min(sockSize / 2, writeBuf.size() - writePos); } else { writeSize = min(min(sockSize / 2, writeBuf.size() - writePos), sendMaximum); } } else { writeSize = min(sockSize / 2, writeBuf.size() - writePos); } int written = sock->write(&writeBuf[writePos], writeSize); if(written > 0) { writePos += written; fire(BufferedSocketListener::BytesSent(), 0, written); if(throttling) { int32_t cycle_time = um->throttleCycleTime(); current = TimerManager::getTick(); int32_t sleep_time = cycle_time - (current - start); if (sleep_time > 0 && sleep_time <= cycle_time) { Thread::sleep(sleep_time); } } } else if(written == -1) { if(!readDone && readPos < readBuf.size()) { // Read a little since we're blocking anyway... size_t bytesRead = min(readBuf.size() - readPos, readBuf.size() / 2); size_t actual = file->read(&readBuf[readPos], bytesRead); if(bytesRead > 0) { fire(BufferedSocketListener::BytesSent(), bytesRead, 0); } if(actual == 0) { readDone = true; } else { readPos += actual; } } else { while(!disconnecting) { int w = sock->wait(POLL_TIMEOUT, Socket::WAIT_WRITE | Socket::WAIT_READ); if(w & Socket::WAIT_READ) { threadRead(); } if(w & Socket::WAIT_WRITE) { break; } } } } } } }