lword NonblockingSink::TimedFlush(unsigned long maxTime, size_t targetSize) { m_blockedBySpeedLimit = false; size_t curBufSize = GetCurrentBufferSize(); if (curBufSize <= targetSize && (targetSize || !EofPending())) return 0; if (!GetMaxBytesPerSecond()) return DoFlush(maxTime, targetSize); bool forever = (maxTime == INFINITE_TIME); unsigned long timeToGo = maxTime; Timer timer(Timer::MILLISECONDS, forever); lword totalFlushed = 0; timer.StartTimer(); while (true) { size_t flushSize = UnsignedMin(curBufSize - targetSize, ComputeCurrentTransceiveLimit()); if (flushSize || EofPending()) { if (!forever) timeToGo = SaturatingSubtract(maxTime, timer.ElapsedTime()); size_t ret = (size_t)DoFlush(timeToGo, curBufSize - flushSize); if (ret) { NoteTransceive(ret); curBufSize -= ret; totalFlushed += ret; } } if (curBufSize <= targetSize && (targetSize || !EofPending())) break; if (!forever) { timeToGo = SaturatingSubtract(maxTime, timer.ElapsedTime()); if (!timeToGo) break; } double waitTime = TimeToNextTransceive(); if (!forever && waitTime > timeToGo) { m_blockedBySpeedLimit = true; break; } WaitObjectContainer container; LimitedBandwidth::GetWaitObjects(container, CallStack("NonblockingSink::TimedFlush() - speed limit", 0)); container.Wait((unsigned long)waitTime); } return totalFlushed; }
size_t MeterFilter::PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable) { if (!m_transparent) return 0; size_t t; FILTER_BEGIN; m_begin = begin; m_length = length; while (m_length > 0 || messageEnd) { if (m_length > 0 && !m_rangesToSkip.empty() && m_rangesToSkip.front().message == m_totalMessages && m_currentMessageBytes + m_length > m_rangesToSkip.front().position) { FILTER_OUTPUT_MAYBE_MODIFIABLE(1, m_begin, t = (size_t)SaturatingSubtract(m_rangesToSkip.front().position, m_currentMessageBytes), false, modifiable); assert(t < m_length); m_begin += t; m_length -= t; m_currentMessageBytes += t; m_totalBytes += t; if (m_currentMessageBytes + m_length < m_rangesToSkip.front().position + m_rangesToSkip.front().size) t = m_length; else { t = (size_t)SaturatingSubtract(m_rangesToSkip.front().position + m_rangesToSkip.front().size, m_currentMessageBytes); assert(t <= m_length); m_rangesToSkip.pop_front(); } m_begin += t; m_length -= t; m_currentMessageBytes += t; m_totalBytes += t; } else { FILTER_OUTPUT_MAYBE_MODIFIABLE(2, m_begin, m_length, messageEnd, modifiable); m_currentMessageBytes += m_length; m_totalBytes += m_length; m_length = 0; if (messageEnd) { m_currentMessageBytes = 0; m_currentSeriesMessages++; m_totalMessages++; messageEnd = false; } } } FILTER_END_NO_MESSAGE_END; }
size_t ArraySink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) { if (m_buf+m_total != begin) memcpy(m_buf+m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total))); m_total += length; return 0; }
word32 RSA_BlockType1::UnPad(const byte* pkcsBlock, word32 pkcsBlockLen, byte* output) const { bool invalid = false; unsigned int maxOutputLen = SaturatingSubtract(pkcsBlockLen / 8, 10U); // convert from bit length to byte length if (pkcsBlockLen % 8 != 0) { invalid = (pkcsBlock[0] != 0) || invalid; pkcsBlock++; } pkcsBlockLen /= 8; // Require block type 1 for SSL. invalid = (pkcsBlock[0] != 1) || invalid; // skip past the padding until we find the separator unsigned i=1; while (i<pkcsBlockLen && pkcsBlock[i++]) { // null body } if (!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) return 0; unsigned int outputLen = pkcsBlockLen - i; invalid = (outputLen > maxOutputLen) || invalid; if (invalid) return 0; memcpy(output, pkcsBlock+i, outputLen); return outputLen; }
double LimitedBandwidth::TimeToNextTransceive() { if (!m_maxBytesPerSecond) return 0; if (!m_nextTransceiveTime) ComputeNextTransceiveTime(); return SaturatingSubtract(m_nextTransceiveTime, m_timer.ElapsedTimeAsDouble()); }
lword LimitedBandwidth::ComputeCurrentTransceiveLimit() { if (!m_maxBytesPerSecond) return ULONG_MAX; double curTime = GetCurTimeAndCleanUp(); CRYPTOPP_UNUSED(curTime); lword total = 0; for (OpQueue::size_type i=0; i!=m_ops.size(); ++i) total += m_ops[i].second; return SaturatingSubtract(m_maxBytesPerSecond, total); }
size_t ArrayXorSink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) { CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); // Avoid passing NULL pointer to xorbuf size_t copied = 0; if (m_buf && begin) { copied = STDMIN(length, SaturatingSubtract(m_size, m_total)); xorbuf(m_buf+m_total, begin, copied); } m_total += copied; return length - copied; }
size_t ArraySink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) { CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); // Avoid passing NULL pointer to memcpy. Using memmove due to // Valgrind finding on overlapping buffers. size_t copied = 0; if (m_buf && begin) { copied = STDMIN(length, SaturatingSubtract(m_size, m_total)); memmove(m_buf+m_total, begin, copied); } m_total += copied; return length - copied; }
void DL_SignatureMessageEncodingMethod_DSA::ComputeMessageRepresentative(RandomNumberGenerator &rng, const byte *recoverableMessage, size_t recoverableMessageLength, HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, byte *representative, size_t representativeBitLength) const { assert(recoverableMessageLength == 0); assert(hashIdentifier.second == 0); const size_t representativeByteLength = BitsToBytes(representativeBitLength); const size_t digestSize = hash.DigestSize(); const size_t paddingLength = SaturatingSubtract(representativeByteLength, digestSize); memset(representative, 0, paddingLength); hash.TruncatedFinal(representative+paddingLength, STDMIN(representativeByteLength, digestSize)); if (digestSize*8 > representativeBitLength) { Integer h(representative, representativeByteLength); h >>= representativeByteLength*8 - representativeBitLength; h.Encode(representative, representativeByteLength); }
bool WaitObjectContainer::Wait(unsigned long milliseconds) { if (m_noWait || (!m_maxFd && !m_firstEventTime)) return true; bool timeoutIsScheduledEvent = false; if (m_firstEventTime) { double timeToFirstEvent = SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble()); if (timeToFirstEvent <= milliseconds) { milliseconds = (unsigned long)timeToFirstEvent; timeoutIsScheduledEvent = true; } } timeval tv, *timeout; if (milliseconds == INFINITE_TIME) timeout = NULL; else { tv.tv_sec = milliseconds / 1000; tv.tv_usec = (milliseconds % 1000) * 1000; timeout = &tv; } int result = select(m_maxFd+1, &m_readfds, &m_writefds, NULL, timeout); if (result > 0) return true; else if (result == 0) return timeoutIsScheduledEvent; else throw Err("WaitObjectContainer: select failed with error " + errno); }
unsigned int PKCS_EncryptionPaddingScheme::MaxUnpaddedLength(unsigned int paddedLength) const { return SaturatingSubtract(paddedLength/8, 10U); }
size_t NetworkSource::DoPump(lword &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter) { NetworkReceiver &receiver = AccessReceiver(); lword maxSize = byteCount; byteCount = 0; bool forever = maxTime == INFINITE_TIME; Timer timer(Timer::MILLISECONDS, forever); BufferedTransformation *t = AttachedTransformation(); if (m_outputBlocked) goto DoOutput; while (true) { if (m_dataBegin == m_dataEnd) { if (receiver.EofReceived()) break; if (m_waitingForResult) { if (receiver.MustWaitForResult() && !receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()), CallStack("NetworkSource::DoPump() - wait receive result", 0))) break; unsigned int recvResult = receiver.GetReceiveResult(); #if CRYPTOPP_TRACE_NETWORK OutputDebugString((IntToString((unsigned int)this) + ": Received " + IntToString(recvResult) + " bytes\n").c_str()); #endif m_dataEnd += recvResult; m_waitingForResult = false; if (!receiver.MustWaitToReceive() && !receiver.EofReceived() && m_dataEnd != m_buf.size()) goto ReceiveNoWait; } else { m_dataEnd = m_dataBegin = 0; if (receiver.MustWaitToReceive()) { if (!receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()), CallStack("NetworkSource::DoPump() - wait receive", 0))) break; receiver.Receive(m_buf+m_dataEnd, m_buf.size()-m_dataEnd); m_waitingForResult = true; } else { ReceiveNoWait: m_waitingForResult = true; // call Receive repeatedly as long as data is immediately available, // because some receivers tend to return data in small pieces #if CRYPTOPP_TRACE_NETWORK OutputDebugString((IntToString((unsigned int)this) + ": Receiving " + IntToString(m_buf.size()-m_dataEnd) + " bytes\n").c_str()); #endif while (receiver.Receive(m_buf+m_dataEnd, m_buf.size()-m_dataEnd)) { unsigned int recvResult = receiver.GetReceiveResult(); #if CRYPTOPP_TRACE_NETWORK OutputDebugString((IntToString((unsigned int)this) + ": Received " + IntToString(recvResult) + " bytes\n").c_str()); #endif m_dataEnd += recvResult; if (receiver.EofReceived() || m_dataEnd > m_buf.size() /2) { m_waitingForResult = false; break; } } } } } else { m_putSize = UnsignedMin(m_dataEnd - m_dataBegin, maxSize - byteCount); if (checkDelimiter) m_putSize = std::find(m_buf+m_dataBegin, m_buf+m_dataBegin+m_putSize, delimiter) - (m_buf+m_dataBegin); DoOutput: size_t result = t->PutModifiable2(m_buf+m_dataBegin, m_putSize, 0, forever || blockingOutput); if (result) { if (t->Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()), CallStack("NetworkSource::DoPump() - wait attachment", 0))) goto DoOutput; else { m_outputBlocked = true; return result; } } m_outputBlocked = false; byteCount += m_putSize; m_dataBegin += m_putSize; if (checkDelimiter && m_dataBegin < m_dataEnd && m_buf[m_dataBegin] == delimiter) break; if (maxSize != ULONG_MAX && byteCount == maxSize) break; // once time limit is reached, return even if there is more data waiting // but make 0 a special case so caller can request a large amount of data to be // pumped as long as it is immediately available if (maxTime > 0 && timer.ElapsedTime() > maxTime) break; } } return 0; }
bool WaitObjectContainer::Wait(unsigned long milliseconds) { if (m_noWait || (m_handles.empty() && !m_firstEventTime)) { SetLastResult(LASTRESULT_NOWAIT); return true; } bool timeoutIsScheduledEvent = false; if (m_firstEventTime) { double timeToFirstEvent = SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble()); if (timeToFirstEvent <= milliseconds) { milliseconds = (unsigned long)timeToFirstEvent; timeoutIsScheduledEvent = true; } if (m_handles.empty() || !milliseconds) { if (milliseconds) Sleep(milliseconds); SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT); return timeoutIsScheduledEvent; } } if (m_handles.size() > MAXIMUM_WAIT_OBJECTS) { // too many wait objects for a single WaitForMultipleObjects call, so use multiple threads static const unsigned int WAIT_OBJECTS_PER_THREAD = MAXIMUM_WAIT_OBJECTS-1; unsigned int nThreads = (unsigned int)((m_handles.size() + WAIT_OBJECTS_PER_THREAD - 1) / WAIT_OBJECTS_PER_THREAD); if (nThreads > MAXIMUM_WAIT_OBJECTS) // still too many wait objects, maybe implement recursive threading later? throw Err("WaitObjectContainer: number of wait objects exceeds limit"); CreateThreads(nThreads); DWORD error = S_OK; for (unsigned int i=0; i<m_threads.size(); i++) { WaitingThreadData &thread = *m_threads[i]; while (!thread.waitingToWait) // spin until thread is in the initial "waiting to wait" state Sleep(0); if (i<nThreads) { thread.waitHandles = &m_handles[i*WAIT_OBJECTS_PER_THREAD]; thread.count = UnsignedMin(WAIT_OBJECTS_PER_THREAD, m_handles.size() - i*WAIT_OBJECTS_PER_THREAD); thread.error = &error; } else thread.count = 0; } ResetEvent(m_stopWaiting); PulseEvent(m_startWaiting); DWORD result = ::WaitForSingleObject(m_stopWaiting, milliseconds); if (result == WAIT_OBJECT_0) { if (error == S_OK) return true; else throw Err("WaitObjectContainer: WaitForMultipleObjects in thread failed with error " + IntToString(error)); } SetEvent(m_stopWaiting); if (result == WAIT_TIMEOUT) { SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT); return timeoutIsScheduledEvent; } else throw Err("WaitObjectContainer: WaitForSingleObject failed with error " + IntToString(::GetLastError())); } else { #if TRACE_WAIT static Timer t(Timer::MICROSECONDS); static unsigned long lastTime = 0; unsigned long timeBeforeWait = t.ElapsedTime(); #endif DWORD result = ::WaitForMultipleObjects((DWORD)m_handles.size(), &m_handles[0], FALSE, milliseconds); #if TRACE_WAIT if (milliseconds > 0) { unsigned long timeAfterWait = t.ElapsedTime(); OutputDebugString(("Handles " + IntToString(m_handles.size()) + ", Woke up by " + IntToString(result-WAIT_OBJECT_0) + ", Busied for " + IntToString(timeBeforeWait-lastTime) + " us, Waited for " + IntToString(timeAfterWait-timeBeforeWait) + " us, max " + IntToString(milliseconds) + "ms\n").c_str()); lastTime = timeAfterWait; } #endif if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size()) { if (result == m_lastResult) m_sameResultCount++; else { m_lastResult = result; m_sameResultCount = 0; } return true; } else if (result == WAIT_TIMEOUT) { SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT); return timeoutIsScheduledEvent; } else throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(::GetLastError())); } }
byte * ArraySink::CreatePutSpace(size_t &size) { size = SaturatingSubtract(m_size, m_total); return m_buf + m_total; }
word32 FixedMaxPlaintextLength() const {return SaturatingSubtract(PaddedBlockBitLength() / 8, 10U); }
lword NetworkSink::DoFlush(unsigned long maxTime, size_t targetSize) { NetworkSender &sender = AccessSender(); bool forever = maxTime == INFINITE_TIME; Timer timer(Timer::MILLISECONDS, forever); unsigned int totalFlushSize = 0; while (true) { if (m_buffer.CurrentSize() <= targetSize) break; if (m_needSendResult) { if (sender.MustWaitForResult() && !sender.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()), CallStack("NetworkSink::DoFlush() - wait send result", 0))) break; unsigned int sendResult = sender.GetSendResult(); #if CRYPTOPP_TRACE_NETWORK OutputDebugString((IntToString((unsigned int)this) + ": Sent " + IntToString(sendResult) + " bytes\n").c_str()); #endif m_buffer.Skip(sendResult); totalFlushSize += sendResult; m_needSendResult = false; if (!m_buffer.AnyRetrievable()) break; } unsigned long timeOut = maxTime ? SaturatingSubtract(maxTime, timer.ElapsedTime()) : 0; if (sender.MustWaitToSend() && !sender.Wait(timeOut, CallStack("NetworkSink::DoFlush() - wait send", 0))) break; size_t contiguousSize = 0; const byte *block = m_buffer.Spy(contiguousSize); #if CRYPTOPP_TRACE_NETWORK OutputDebugString((IntToString((unsigned int)this) + ": Sending " + IntToString(contiguousSize) + " bytes\n").c_str()); #endif sender.Send(block, contiguousSize); m_needSendResult = true; if (maxTime > 0 && timeOut == 0) break; // once time limit is reached, return even if there is more data waiting } m_byteCountSinceLastTimerReset += totalFlushSize; ComputeCurrentSpeed(); if (m_buffer.IsEmpty() && !m_needSendResult) { if (m_eofState == EOF_PENDING_SEND) { sender.SendEof(); m_eofState = sender.MustWaitForEof() ? EOF_PENDING_DELIVERY : EOF_DONE; } while (m_eofState == EOF_PENDING_DELIVERY) { unsigned long timeOut = maxTime ? SaturatingSubtract(maxTime, timer.ElapsedTime()) : 0; if (!sender.Wait(timeOut, CallStack("NetworkSink::DoFlush() - wait EOF", 0))) break; if (sender.EofSent()) m_eofState = EOF_DONE; } } return totalFlushSize; }
size_t PSSR_MEM_Base::MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const { if (AllowRecovery()) return SaturatingSubtract(representativeBitLength, MinRepresentativeBitLength(hashIdentifierLength, digestLength)) / 8; return 0; }
size_t OAEP_Base::MaxUnpaddedLength(size_t paddedLength) const { return SaturatingSubtract(paddedLength/8, 1+2*DigestSize()); }
size_t NonblockingSource::GeneralPump2( lword& byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter) { m_blockedBySpeedLimit = false; if (!GetMaxBytesPerSecond()) { size_t ret = DoPump(byteCount, blockingOutput, maxTime, checkDelimiter, delimiter); m_doPumpBlocked = (ret != 0); return ret; } bool forever = (maxTime == INFINITE_TIME); unsigned long timeToGo = maxTime; Timer timer(Timer::MILLISECONDS, forever); lword maxSize = byteCount; byteCount = 0; timer.StartTimer(); while (true) { lword curMaxSize = UnsignedMin(ComputeCurrentTransceiveLimit(), maxSize - byteCount); if (curMaxSize || m_doPumpBlocked) { if (!forever) timeToGo = SaturatingSubtract(maxTime, timer.ElapsedTime()); size_t ret = DoPump(curMaxSize, blockingOutput, timeToGo, checkDelimiter, delimiter); m_doPumpBlocked = (ret != 0); if (curMaxSize) { NoteTransceive(curMaxSize); byteCount += curMaxSize; } if (ret) return ret; } if (maxSize != ULONG_MAX && byteCount >= maxSize) break; if (!forever) { timeToGo = SaturatingSubtract(maxTime, timer.ElapsedTime()); if (!timeToGo) break; } double waitTime = TimeToNextTransceive(); if (!forever && waitTime > timeToGo) { m_blockedBySpeedLimit = true; break; } WaitObjectContainer container; LimitedBandwidth::GetWaitObjects(container, CallStack("NonblockingSource::GeneralPump2() - speed limit", 0)); container.Wait((unsigned long)waitTime); } return 0; }
unsigned int ArrayXorSink::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking) { xorbuf(m_buf+m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total))); m_total += length; return 0; }