merge in changes by denis bider and fix compile on gcc 3.4.4 and MSVC 6
parent
254b0f0d4d
commit
6aacd0a0de
|
|
@ -179,11 +179,11 @@ unsigned int BufferedTransformation::GetMaxWaitObjectCount() const
|
||||||
return t ? t->GetMaxWaitObjectCount() : 0;
|
return t ? t->GetMaxWaitObjectCount() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferedTransformation::GetWaitObjects(WaitObjectContainer &container)
|
void BufferedTransformation::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
BufferedTransformation *t = AttachedTransformation();
|
BufferedTransformation *t = AttachedTransformation();
|
||||||
if (t)
|
if (t)
|
||||||
t->GetWaitObjects(container);
|
t->GetWaitObjects(container, callStack); // reduce clutter by not adding to stack here
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferedTransformation::Initialize(const NameValuePairs ¶meters, int propagation)
|
void BufferedTransformation::Initialize(const NameValuePairs ¶meters, int propagation)
|
||||||
|
|
|
||||||
11
cryptlib.h
11
cryptlib.h
|
|
@ -661,6 +661,7 @@ public:
|
||||||
CRYPTOPP_DLL RandomNumberGenerator & CRYPTOPP_API NullRNG();
|
CRYPTOPP_DLL RandomNumberGenerator & CRYPTOPP_API NullRNG();
|
||||||
|
|
||||||
class WaitObjectContainer;
|
class WaitObjectContainer;
|
||||||
|
class CallStack;
|
||||||
|
|
||||||
//! interface for objects that you can wait for
|
//! interface for objects that you can wait for
|
||||||
|
|
||||||
|
|
@ -670,10 +671,14 @@ public:
|
||||||
//! maximum number of wait objects that this object can return
|
//! maximum number of wait objects that this object can return
|
||||||
virtual unsigned int GetMaxWaitObjectCount() const =0;
|
virtual unsigned int GetMaxWaitObjectCount() const =0;
|
||||||
//! put wait objects into container
|
//! put wait objects into container
|
||||||
virtual void GetWaitObjects(WaitObjectContainer &container) =0;
|
/*! \param callStack is used for tracing no wait loops, example:
|
||||||
|
something.GetWaitObjects(c, CallStack("my func after X", 0));
|
||||||
|
- or in an outer GetWaitObjects() method that itself takes a callStack parameter:
|
||||||
|
innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack)); */
|
||||||
|
virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) =0;
|
||||||
//! wait on this object
|
//! wait on this object
|
||||||
/*! same as creating an empty container, calling GetWaitObjects(), and calling Wait() on the container */
|
/*! same as creating an empty container, calling GetWaitObjects(), and calling Wait() on the container */
|
||||||
bool Wait(unsigned long milliseconds);
|
bool Wait(unsigned long milliseconds, CallStack const& callStack);
|
||||||
};
|
};
|
||||||
|
|
||||||
//! interface for buffered transformations
|
//! interface for buffered transformations
|
||||||
|
|
@ -761,7 +766,7 @@ public:
|
||||||
//! \name WAITING
|
//! \name WAITING
|
||||||
//@{
|
//@{
|
||||||
unsigned int GetMaxWaitObjectCount() const;
|
unsigned int GetMaxWaitObjectCount() const;
|
||||||
void GetWaitObjects(WaitObjectContainer &container);
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//! \name SIGNALS
|
//! \name SIGNALS
|
||||||
|
|
|
||||||
|
|
@ -420,8 +420,8 @@ public:
|
||||||
|
|
||||||
unsigned int GetMaxWaitObjectCount() const
|
unsigned int GetMaxWaitObjectCount() const
|
||||||
{ return m_target && GetPassWaitObjects() ? m_target->GetMaxWaitObjectCount() : 0; }
|
{ return m_target && GetPassWaitObjects() ? m_target->GetMaxWaitObjectCount() : 0; }
|
||||||
void GetWaitObjects(WaitObjectContainer &container)
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
{ if (m_target && GetPassWaitObjects()) m_target->GetWaitObjects(container); }
|
{ if (m_target && GetPassWaitObjects()) m_target->GetWaitObjects(container, callStack); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BufferedTransformation *m_target;
|
BufferedTransformation *m_target;
|
||||||
|
|
|
||||||
14
hrtimer.cpp
14
hrtimer.cpp
|
|
@ -34,7 +34,7 @@ double TimerBase::ConvertTo(word64 t, Unit unit)
|
||||||
|
|
||||||
void TimerBase::StartTimer()
|
void TimerBase::StartTimer()
|
||||||
{
|
{
|
||||||
m_start = GetCurrentTimerValue();
|
m_last = m_start = GetCurrentTimerValue();
|
||||||
m_started = true;
|
m_started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,14 +42,18 @@ double TimerBase::ElapsedTimeAsDouble()
|
||||||
{
|
{
|
||||||
if (m_stuckAtZero)
|
if (m_stuckAtZero)
|
||||||
return 0;
|
return 0;
|
||||||
else if (m_started)
|
|
||||||
return ConvertTo(GetCurrentTimerValue() - m_start, m_timerUnit);
|
if (m_started)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
word64 now = GetCurrentTimerValue();
|
||||||
|
if (m_last < now) // protect against OS bugs where time goes backwards
|
||||||
|
m_last = now;
|
||||||
|
return ConvertTo(m_last - m_start, m_timerUnit);
|
||||||
|
}
|
||||||
|
|
||||||
StartTimer();
|
StartTimer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long TimerBase::ElapsedTime()
|
unsigned long TimerBase::ElapsedTime()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ private:
|
||||||
|
|
||||||
Unit m_timerUnit; // HPUX workaround: m_unit is a system macro on HPUX
|
Unit m_timerUnit; // HPUX workaround: m_unit is a system macro on HPUX
|
||||||
bool m_stuckAtZero, m_started;
|
bool m_stuckAtZero, m_started;
|
||||||
word64 m_start;
|
word64 m_start, m_last;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! measure CPU time spent executing instructions of this thread (if supported by OS)
|
//! measure CPU time spent executing instructions of this thread (if supported by OS)
|
||||||
|
|
|
||||||
18
misc.h
18
misc.h
|
|
@ -116,6 +116,22 @@ retry:
|
||||||
|
|
||||||
// ************** misc functions ***************
|
// ************** misc functions ***************
|
||||||
|
|
||||||
|
#if (!__STDC_WANT_SECURE_LIB__)
|
||||||
|
inline void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
|
||||||
|
{
|
||||||
|
if (count > sizeInBytes)
|
||||||
|
throw InvalidArgument("memcpy_s: buffer overflow");
|
||||||
|
memcpy(dest, src, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void memmove_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
|
||||||
|
{
|
||||||
|
if (count > sizeInBytes)
|
||||||
|
throw InvalidArgument("memmove_s: buffer overflow");
|
||||||
|
memmove(dest, src, count);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// can't use std::min or std::max in MSVC60 or Cygwin 1.1.0
|
// can't use std::min or std::max in MSVC60 or Cygwin 1.1.0
|
||||||
template <class T> inline const T& STDMIN(const T& a, const T& b)
|
template <class T> inline const T& STDMIN(const T& a, const T& b)
|
||||||
{
|
{
|
||||||
|
|
@ -331,8 +347,6 @@ std::string IntToString(T a, unsigned int base = 10)
|
||||||
template <class T1, class T2>
|
template <class T1, class T2>
|
||||||
inline T1 SaturatingSubtract(const T1 &a, const T2 &b)
|
inline T1 SaturatingSubtract(const T1 &a, const T2 &b)
|
||||||
{
|
{
|
||||||
CRYPTOPP_COMPILE_ASSERT_INSTANCE(T1(-1)>0, 0); // T1 is unsigned type
|
|
||||||
CRYPTOPP_COMPILE_ASSERT_INSTANCE(T2(-1)>0, 1); // T2 is unsigned type
|
|
||||||
return T1((a > b) ? (a - b) : 0);
|
return T1((a > b) ? (a - b) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
319
network.cpp
319
network.cpp
|
|
@ -8,6 +8,133 @@
|
||||||
|
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
lword LimitedBandwidth::ComputeCurrentTransceiveLimit()
|
||||||
|
{
|
||||||
|
if (!m_maxBytesPerSecond)
|
||||||
|
return ULONG_MAX;
|
||||||
|
|
||||||
|
double curTime = GetCurTimeAndCleanUp();
|
||||||
|
lword total = 0;
|
||||||
|
for (OpQueue::size_type i=0; i!=m_ops.size(); ++i)
|
||||||
|
total += m_ops[i].second;
|
||||||
|
return SaturatingSubtract(m_maxBytesPerSecond, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
double LimitedBandwidth::TimeToNextTransceive()
|
||||||
|
{
|
||||||
|
if (!m_maxBytesPerSecond)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!m_nextTransceiveTime)
|
||||||
|
ComputeNextTransceiveTime();
|
||||||
|
|
||||||
|
return SaturatingSubtract(m_nextTransceiveTime, m_timer.ElapsedTimeAsDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimitedBandwidth::NoteTransceive(lword size)
|
||||||
|
{
|
||||||
|
if (m_maxBytesPerSecond)
|
||||||
|
{
|
||||||
|
double curTime = GetCurTimeAndCleanUp();
|
||||||
|
m_ops.push_back(std::make_pair(curTime, size));
|
||||||
|
m_nextTransceiveTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimitedBandwidth::ComputeNextTransceiveTime()
|
||||||
|
{
|
||||||
|
double curTime = GetCurTimeAndCleanUp();
|
||||||
|
lword total = 0;
|
||||||
|
for (unsigned int i=0; i!=m_ops.size(); ++i)
|
||||||
|
total += m_ops[i].second;
|
||||||
|
m_nextTransceiveTime =
|
||||||
|
(total < m_maxBytesPerSecond) ? curTime : m_ops.front().first + 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
double LimitedBandwidth::GetCurTimeAndCleanUp()
|
||||||
|
{
|
||||||
|
if (!m_maxBytesPerSecond)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
double curTime = m_timer.ElapsedTimeAsDouble();
|
||||||
|
while (m_ops.size() && (m_ops.front().first + 1000 < curTime))
|
||||||
|
m_ops.pop_front();
|
||||||
|
return curTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimitedBandwidth::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
|
{
|
||||||
|
double nextTransceiveTime = TimeToNextTransceive();
|
||||||
|
if (nextTransceiveTime)
|
||||||
|
container.ScheduleEvent(nextTransceiveTime, CallStack("LimitedBandwidth::GetWaitObjects()", &callStack));
|
||||||
|
}
|
||||||
|
|
||||||
|
// *************************************************************
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
size_t NonblockingSource::PumpMessages2(unsigned int &messageCount, bool blocking)
|
size_t NonblockingSource::PumpMessages2(unsigned int &messageCount, bool blocking)
|
||||||
{
|
{
|
||||||
if (messageCount == 0)
|
if (messageCount == 0)
|
||||||
|
|
@ -30,10 +157,68 @@ size_t NonblockingSource::PumpMessages2(unsigned int &messageCount, bool blockin
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
bool NonblockingSink::IsolatedFlush(bool hardFlush, bool blocking)
|
bool NonblockingSink::IsolatedFlush(bool hardFlush, bool blocking)
|
||||||
{
|
{
|
||||||
TimedFlush(blocking ? INFINITE_TIME : 0);
|
TimedFlush(blocking ? INFINITE_TIME : 0);
|
||||||
return hardFlush && !!GetCurrentBufferSize();
|
return hardFlush && (!!GetCurrentBufferSize() || EofPending());
|
||||||
}
|
}
|
||||||
|
|
||||||
// *************************************************************
|
// *************************************************************
|
||||||
|
|
@ -47,19 +232,29 @@ NetworkSource::NetworkSource(BufferedTransformation *attachment)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSource::GetWaitObjects(WaitObjectContainer &container)
|
unsigned int NetworkSource::GetMaxWaitObjectCount() const
|
||||||
{
|
{
|
||||||
if (!m_outputBlocked)
|
return LimitedBandwidth::GetMaxWaitObjectCount()
|
||||||
{
|
+ GetReceiver().GetMaxWaitObjectCount()
|
||||||
if (m_dataBegin == m_dataEnd)
|
+ AttachedTransformation()->GetMaxWaitObjectCount();
|
||||||
AccessReceiver().GetWaitObjects(container);
|
|
||||||
else
|
|
||||||
container.SetNoWait();
|
|
||||||
}
|
|
||||||
AttachedTransformation()->GetWaitObjects(container);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NetworkSource::GeneralPump2(lword &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter)
|
void NetworkSource::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
|
{
|
||||||
|
if (BlockedBySpeedLimit())
|
||||||
|
LimitedBandwidth::GetWaitObjects(container, CallStack("NetworkSource::GetWaitObjects() - speed limit", &callStack));
|
||||||
|
else if (!m_outputBlocked)
|
||||||
|
{
|
||||||
|
if (m_dataBegin == m_dataEnd)
|
||||||
|
AccessReceiver().GetWaitObjects(container, CallStack("NetworkSource::GetWaitObjects() - no data", &callStack));
|
||||||
|
else
|
||||||
|
container.SetNoWait(CallStack("NetworkSource::GetWaitObjects() - have data", &callStack));
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachedTransformation()->GetWaitObjects(container, CallStack("NetworkSource::GetWaitObjects() - attachment", &callStack));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NetworkSource::DoPump(lword &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter)
|
||||||
{
|
{
|
||||||
NetworkReceiver &receiver = AccessReceiver();
|
NetworkReceiver &receiver = AccessReceiver();
|
||||||
|
|
||||||
|
|
@ -81,7 +276,9 @@ size_t NetworkSource::GeneralPump2(lword &byteCount, bool blockingOutput, unsign
|
||||||
|
|
||||||
if (m_waitingForResult)
|
if (m_waitingForResult)
|
||||||
{
|
{
|
||||||
if (receiver.MustWaitForResult() && !receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
|
if (receiver.MustWaitForResult() &&
|
||||||
|
!receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()),
|
||||||
|
CallStack("NetworkSource::DoPump() - wait receive result", 0)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
unsigned int recvResult = receiver.GetReceiveResult();
|
unsigned int recvResult = receiver.GetReceiveResult();
|
||||||
|
|
@ -100,7 +297,8 @@ size_t NetworkSource::GeneralPump2(lword &byteCount, bool blockingOutput, unsign
|
||||||
|
|
||||||
if (receiver.MustWaitToReceive())
|
if (receiver.MustWaitToReceive())
|
||||||
{
|
{
|
||||||
if (!receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
|
if (!receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()),
|
||||||
|
CallStack("NetworkSource::DoPump() - wait receive", 0)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
receiver.Receive(m_buf+m_dataEnd, m_buf.size()-m_dataEnd);
|
receiver.Receive(m_buf+m_dataEnd, m_buf.size()-m_dataEnd);
|
||||||
|
|
@ -133,7 +331,8 @@ ReceiveNoWait:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_putSize = (size_t)STDMIN((lword)m_dataEnd-m_dataBegin, maxSize-byteCount);
|
m_putSize = UnsignedMin(m_dataEnd - m_dataBegin, maxSize - byteCount);
|
||||||
|
|
||||||
if (checkDelimiter)
|
if (checkDelimiter)
|
||||||
m_putSize = std::find(m_buf+m_dataBegin, m_buf+m_dataBegin+m_putSize, delimiter) - (m_buf+m_dataBegin);
|
m_putSize = std::find(m_buf+m_dataBegin, m_buf+m_dataBegin+m_putSize, delimiter) - (m_buf+m_dataBegin);
|
||||||
|
|
||||||
|
|
@ -141,7 +340,8 @@ DoOutput:
|
||||||
size_t result = t->PutModifiable2(m_buf+m_dataBegin, m_putSize, 0, forever || blockingOutput);
|
size_t result = t->PutModifiable2(m_buf+m_dataBegin, m_putSize, 0, forever || blockingOutput);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
if (t->Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
|
if (t->Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()),
|
||||||
|
CallStack("NetworkSource::DoPump() - wait attachment", 0)))
|
||||||
goto DoOutput;
|
goto DoOutput;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -155,7 +355,7 @@ DoOutput:
|
||||||
m_dataBegin += m_putSize;
|
m_dataBegin += m_putSize;
|
||||||
if (checkDelimiter && m_dataBegin < m_dataEnd && m_buf[m_dataBegin] == delimiter)
|
if (checkDelimiter && m_dataBegin < m_dataEnd && m_buf[m_dataBegin] == delimiter)
|
||||||
break;
|
break;
|
||||||
if (byteCount == maxSize)
|
if (maxSize != ULONG_MAX && byteCount == maxSize)
|
||||||
break;
|
break;
|
||||||
// once time limit is reached, return even if there is more data waiting
|
// 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
|
// but make 0 a special case so caller can request a large amount of data to be
|
||||||
|
|
@ -172,7 +372,7 @@ DoOutput:
|
||||||
|
|
||||||
NetworkSink::NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound)
|
NetworkSink::NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound)
|
||||||
: m_maxBufferSize(maxBufferSize), m_autoFlushBound(autoFlushBound)
|
: m_maxBufferSize(maxBufferSize), m_autoFlushBound(autoFlushBound)
|
||||||
, m_needSendResult(false), m_wasBlocked(false)
|
, m_needSendResult(false), m_wasBlocked(false), m_eofState(EOF_NONE)
|
||||||
, m_buffer(STDMIN(16U*1024U+256, maxBufferSize)), m_skipBytes(0)
|
, m_buffer(STDMIN(16U*1024U+256, maxBufferSize)), m_skipBytes(0)
|
||||||
, m_speedTimer(Timer::MILLISECONDS), m_byteCountSinceLastTimerReset(0)
|
, m_speedTimer(Timer::MILLISECONDS), m_byteCountSinceLastTimerReset(0)
|
||||||
, m_currentSpeed(0), m_maxObservedSpeed(0)
|
, m_currentSpeed(0), m_maxObservedSpeed(0)
|
||||||
|
|
@ -192,7 +392,42 @@ float NetworkSink::ComputeCurrentSpeed()
|
||||||
return m_currentSpeed;
|
return m_currentSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float NetworkSink::GetMaxObservedSpeed() const
|
||||||
|
{
|
||||||
|
lword m = GetMaxBytesPerSecond();
|
||||||
|
return m ? STDMIN(m_maxObservedSpeed, float(m)) : m_maxObservedSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NetworkSink::GetMaxWaitObjectCount() const
|
||||||
|
{
|
||||||
|
return LimitedBandwidth::GetMaxWaitObjectCount() + GetSender().GetMaxWaitObjectCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSink::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
|
{
|
||||||
|
if (BlockedBySpeedLimit())
|
||||||
|
LimitedBandwidth::GetWaitObjects(container, CallStack("NetworkSink::GetWaitObjects() - speed limit", &callStack));
|
||||||
|
else if (m_wasBlocked)
|
||||||
|
AccessSender().GetWaitObjects(container, CallStack("NetworkSink::GetWaitObjects() - was blocked", &callStack));
|
||||||
|
else if (!m_buffer.IsEmpty())
|
||||||
|
AccessSender().GetWaitObjects(container, CallStack("NetworkSink::GetWaitObjects() - buffer not empty", &callStack));
|
||||||
|
else if (EofPending())
|
||||||
|
AccessSender().GetWaitObjects(container, CallStack("NetworkSink::GetWaitObjects() - EOF pending", &callStack));
|
||||||
|
}
|
||||||
|
|
||||||
size_t NetworkSink::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
|
size_t NetworkSink::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
|
||||||
|
{
|
||||||
|
if (m_eofState == EOF_DONE)
|
||||||
|
{
|
||||||
|
if (length || messageEnd)
|
||||||
|
throw Exception(Exception::OTHER_ERROR, "NetworkSink::Put2() being called after EOF had been sent");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_eofState > EOF_NONE)
|
||||||
|
goto EofSite;
|
||||||
|
|
||||||
{
|
{
|
||||||
if (m_skipBytes)
|
if (m_skipBytes)
|
||||||
{
|
{
|
||||||
|
|
@ -200,7 +435,8 @@ size_t NetworkSink::Put2(const byte *inString, size_t length, int messageEnd, bo
|
||||||
inString += m_skipBytes;
|
inString += m_skipBytes;
|
||||||
length -= m_skipBytes;
|
length -= m_skipBytes;
|
||||||
}
|
}
|
||||||
m_buffer.LazyPut(inString, length);
|
|
||||||
|
m_buffer.Put(inString, length);
|
||||||
|
|
||||||
if (!blocking || m_buffer.CurrentSize() > m_autoFlushBound)
|
if (!blocking || m_buffer.CurrentSize() > m_autoFlushBound)
|
||||||
TimedFlush(0, 0);
|
TimedFlush(0, 0);
|
||||||
|
|
@ -212,24 +448,30 @@ size_t NetworkSink::Put2(const byte *inString, size_t length, int messageEnd, bo
|
||||||
if (m_buffer.CurrentSize() > targetSize)
|
if (m_buffer.CurrentSize() > targetSize)
|
||||||
{
|
{
|
||||||
assert(!blocking);
|
assert(!blocking);
|
||||||
size_t blockedBytes = (size_t)STDMIN(m_buffer.CurrentSize() - targetSize, (lword)length);
|
|
||||||
m_buffer.UndoLazyPut(blockedBytes);
|
|
||||||
m_buffer.FinalizeLazyPut();
|
|
||||||
m_wasBlocked = true;
|
m_wasBlocked = true;
|
||||||
m_skipBytes += length - blockedBytes;
|
m_skipBytes += length;
|
||||||
return UnsignedMin(1, blockedBytes);
|
size_t blockedBytes = UnsignedMin(length, m_buffer.CurrentSize() - targetSize);
|
||||||
|
return STDMAX<size_t>(blockedBytes, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buffer.FinalizeLazyPut();
|
|
||||||
m_wasBlocked = false;
|
m_wasBlocked = false;
|
||||||
m_skipBytes = 0;
|
m_skipBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (messageEnd)
|
if (messageEnd)
|
||||||
AccessSender().SendEof();
|
{
|
||||||
|
m_eofState = EOF_PENDING_SEND;
|
||||||
|
|
||||||
|
EofSite:
|
||||||
|
TimedFlush(blocking ? INFINITE_TIME : 0, 0);
|
||||||
|
if (m_eofState != EOF_DONE)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lword NetworkSink::TimedFlush(unsigned long maxTime, size_t targetSize)
|
lword NetworkSink::DoFlush(unsigned long maxTime, size_t targetSize)
|
||||||
{
|
{
|
||||||
NetworkSender &sender = AccessSender();
|
NetworkSender &sender = AccessSender();
|
||||||
|
|
||||||
|
|
@ -244,7 +486,9 @@ lword NetworkSink::TimedFlush(unsigned long maxTime, size_t targetSize)
|
||||||
|
|
||||||
if (m_needSendResult)
|
if (m_needSendResult)
|
||||||
{
|
{
|
||||||
if (sender.MustWaitForResult() && !sender.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
|
if (sender.MustWaitForResult() &&
|
||||||
|
!sender.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime()),
|
||||||
|
CallStack("NetworkSink::DoFlush() - wait send result", 0)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
unsigned int sendResult = sender.GetSendResult();
|
unsigned int sendResult = sender.GetSendResult();
|
||||||
|
|
@ -260,7 +504,7 @@ lword NetworkSink::TimedFlush(unsigned long maxTime, size_t targetSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long timeOut = maxTime ? SaturatingSubtract(maxTime, timer.ElapsedTime()) : 0;
|
unsigned long timeOut = maxTime ? SaturatingSubtract(maxTime, timer.ElapsedTime()) : 0;
|
||||||
if (sender.MustWaitToSend() && !sender.Wait(timeOut))
|
if (sender.MustWaitToSend() && !sender.Wait(timeOut, CallStack("NetworkSink::DoFlush() - wait send", 0)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
size_t contiguousSize = 0;
|
size_t contiguousSize = 0;
|
||||||
|
|
@ -279,6 +523,25 @@ lword NetworkSink::TimedFlush(unsigned long maxTime, size_t targetSize)
|
||||||
m_byteCountSinceLastTimerReset += totalFlushSize;
|
m_byteCountSinceLastTimerReset += totalFlushSize;
|
||||||
ComputeCurrentSpeed();
|
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;
|
return totalFlushSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
97
network.h
97
network.h
|
|
@ -4,21 +4,62 @@
|
||||||
#include "filters.h"
|
#include "filters.h"
|
||||||
#include "hrtimer.h"
|
#include "hrtimer.h"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
class LimitedBandwidth
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LimitedBandwidth(lword maxBytesPerSecond = 0)
|
||||||
|
: m_maxBytesPerSecond(maxBytesPerSecond), m_timer(Timer::MILLISECONDS)
|
||||||
|
, m_nextTransceiveTime(0)
|
||||||
|
{ m_timer.StartTimer(); }
|
||||||
|
|
||||||
|
lword GetMaxBytesPerSecond() const
|
||||||
|
{ return m_maxBytesPerSecond; }
|
||||||
|
|
||||||
|
void SetMaxBytesPerSecond(lword v)
|
||||||
|
{ m_maxBytesPerSecond = v; }
|
||||||
|
|
||||||
|
lword ComputeCurrentTransceiveLimit();
|
||||||
|
|
||||||
|
double TimeToNextTransceive();
|
||||||
|
|
||||||
|
void NoteTransceive(lword size);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*! GetWaitObjects() must be called despite the 0 return from GetMaxWaitObjectCount();
|
||||||
|
the 0 is because the ScheduleEvent() method is used instead of adding a wait object */
|
||||||
|
unsigned int GetMaxWaitObjectCount() const { return 0; }
|
||||||
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
|
|
||||||
|
private:
|
||||||
|
lword m_maxBytesPerSecond;
|
||||||
|
|
||||||
|
typedef std::deque<std::pair<double, lword> > OpQueue;
|
||||||
|
OpQueue m_ops;
|
||||||
|
|
||||||
|
Timer m_timer;
|
||||||
|
double m_nextTransceiveTime;
|
||||||
|
|
||||||
|
void ComputeNextTransceiveTime();
|
||||||
|
double GetCurTimeAndCleanUp();
|
||||||
|
};
|
||||||
|
|
||||||
//! a Source class that can pump from a device for a specified amount of time.
|
//! a Source class that can pump from a device for a specified amount of time.
|
||||||
class CRYPTOPP_NO_VTABLE NonblockingSource : public AutoSignaling<Source>
|
class CRYPTOPP_NO_VTABLE NonblockingSource : public AutoSignaling<Source>, public LimitedBandwidth
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NonblockingSource(BufferedTransformation *attachment)
|
NonblockingSource(BufferedTransformation *attachment)
|
||||||
: m_messageEndSent(false) {Detach(attachment);}
|
: m_messageEndSent(false) , m_doPumpBlocked(false), m_blockedBySpeedLimit(false) {Detach(attachment);}
|
||||||
|
|
||||||
//! \name NONBLOCKING SOURCE
|
//! \name NONBLOCKING SOURCE
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! pump up to maxSize bytes using at most maxTime milliseconds
|
//! pump up to maxSize bytes using at most maxTime milliseconds
|
||||||
/*! If checkDelimiter is true, pump up to delimiter, which itself is not extracted or pumped. */
|
/*! If checkDelimiter is true, pump up to delimiter, which itself is not extracted or pumped. */
|
||||||
virtual size_t GeneralPump2(lword &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n') =0;
|
size_t GeneralPump2(lword &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n');
|
||||||
|
|
||||||
lword GeneralPump(lword maxSize=LWORD_MAX, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n')
|
lword GeneralPump(lword maxSize=LWORD_MAX, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n')
|
||||||
{
|
{
|
||||||
|
|
@ -35,8 +76,14 @@ public:
|
||||||
size_t PumpMessages2(unsigned int &messageCount, bool blocking=true);
|
size_t PumpMessages2(unsigned int &messageCount, bool blocking=true);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual size_t DoPump(lword &byteCount, bool blockingOutput,
|
||||||
|
unsigned long maxTime, bool checkDelimiter, byte delimiter) =0;
|
||||||
|
|
||||||
|
bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_messageEndSent;
|
bool m_messageEndSent, m_doPumpBlocked, m_blockedBySpeedLimit;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Network Receiver
|
//! Network Receiver
|
||||||
|
|
@ -57,6 +104,7 @@ public:
|
||||||
virtual ~NonblockingSinkInfo() {}
|
virtual ~NonblockingSinkInfo() {}
|
||||||
virtual size_t GetMaxBufferSize() const =0;
|
virtual size_t GetMaxBufferSize() const =0;
|
||||||
virtual size_t GetCurrentBufferSize() const =0;
|
virtual size_t GetCurrentBufferSize() const =0;
|
||||||
|
virtual bool EofPending() const =0;
|
||||||
//! compute the current speed of this sink in bytes per second
|
//! compute the current speed of this sink in bytes per second
|
||||||
virtual float ComputeCurrentSpeed() =0;
|
virtual float ComputeCurrentSpeed() =0;
|
||||||
//! get the maximum observed speed of this sink in bytes per second
|
//! get the maximum observed speed of this sink in bytes per second
|
||||||
|
|
@ -64,9 +112,11 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
//! a Sink class that queues input and can flush to a device for a specified amount of time.
|
//! a Sink class that queues input and can flush to a device for a specified amount of time.
|
||||||
class CRYPTOPP_NO_VTABLE NonblockingSink : public Sink, public NonblockingSinkInfo
|
class CRYPTOPP_NO_VTABLE NonblockingSink : public Sink, public NonblockingSinkInfo, public LimitedBandwidth
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
NonblockingSink() : m_blockedBySpeedLimit(false) {}
|
||||||
|
|
||||||
bool IsolatedFlush(bool hardFlush, bool blocking);
|
bool IsolatedFlush(bool hardFlush, bool blocking);
|
||||||
|
|
||||||
//! flush to device for no more than maxTime milliseconds
|
//! flush to device for no more than maxTime milliseconds
|
||||||
|
|
@ -79,11 +129,19 @@ public:
|
||||||
For example: while (sink.TimedFlush(0) > 0) {}
|
For example: while (sink.TimedFlush(0) > 0) {}
|
||||||
\return number of bytes flushed
|
\return number of bytes flushed
|
||||||
*/
|
*/
|
||||||
virtual lword TimedFlush(unsigned long maxTime, size_t targetSize=0) =0;
|
lword TimedFlush(unsigned long maxTime, size_t targetSize = 0);
|
||||||
|
|
||||||
virtual void SetMaxBufferSize(size_t maxBufferSize) =0;
|
virtual void SetMaxBufferSize(size_t maxBufferSize) =0;
|
||||||
//! set a bound which will cause sink to flush if exceeded by GetCurrentBufferSize()
|
//! set a bound which will cause sink to flush if exceeded by GetCurrentBufferSize()
|
||||||
virtual void SetAutoFlushBound(size_t bound) =0;
|
virtual void SetAutoFlushBound(size_t bound) =0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual lword DoFlush(unsigned long maxTime, size_t targetSize) = 0;
|
||||||
|
|
||||||
|
bool BlockedBySpeedLimit() const { return m_blockedBySpeedLimit; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_blockedBySpeedLimit;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Network Sender
|
//! Network Sender
|
||||||
|
|
@ -94,7 +152,9 @@ public:
|
||||||
virtual bool MustWaitForResult() {return false;}
|
virtual bool MustWaitForResult() {return false;}
|
||||||
virtual void Send(const byte* buf, size_t bufLen) =0;
|
virtual void Send(const byte* buf, size_t bufLen) =0;
|
||||||
virtual unsigned int GetSendResult() =0;
|
virtual unsigned int GetSendResult() =0;
|
||||||
|
virtual bool MustWaitForEof() {return false;}
|
||||||
virtual void SendEof() =0;
|
virtual void SendEof() =0;
|
||||||
|
virtual bool EofSent() {return false;} // implement if MustWaitForEof() == true
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HIGHRES_TIMER_AVAILABLE
|
#ifdef HIGHRES_TIMER_AVAILABLE
|
||||||
|
|
@ -105,14 +165,14 @@ class CRYPTOPP_NO_VTABLE NetworkSource : public NonblockingSource
|
||||||
public:
|
public:
|
||||||
NetworkSource(BufferedTransformation *attachment);
|
NetworkSource(BufferedTransformation *attachment);
|
||||||
|
|
||||||
unsigned int GetMaxWaitObjectCount() const
|
unsigned int GetMaxWaitObjectCount() const;
|
||||||
{return GetReceiver().GetMaxWaitObjectCount() + AttachedTransformation()->GetMaxWaitObjectCount();}
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
void GetWaitObjects(WaitObjectContainer &container);
|
|
||||||
|
|
||||||
size_t GeneralPump2(lword &byteCount, bool blockingOutput=true, unsigned long maxTime=INFINITE_TIME, bool checkDelimiter=false, byte delimiter='\n');
|
|
||||||
bool SourceExhausted() const {return m_dataBegin == m_dataEnd && GetReceiver().EofReceived();}
|
bool SourceExhausted() const {return m_dataBegin == m_dataEnd && GetReceiver().EofReceived();}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
size_t DoPump(lword &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter);
|
||||||
|
|
||||||
virtual NetworkReceiver & AccessReceiver() =0;
|
virtual NetworkReceiver & AccessReceiver() =0;
|
||||||
const NetworkReceiver & GetReceiver() const {return const_cast<NetworkSource *>(this)->AccessReceiver();}
|
const NetworkReceiver & GetReceiver() const {return const_cast<NetworkSource *>(this)->AccessReceiver();}
|
||||||
|
|
||||||
|
|
@ -128,15 +188,11 @@ class CRYPTOPP_NO_VTABLE NetworkSink : public NonblockingSink
|
||||||
public:
|
public:
|
||||||
NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound);
|
NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound);
|
||||||
|
|
||||||
unsigned int GetMaxWaitObjectCount() const
|
unsigned int GetMaxWaitObjectCount() const;
|
||||||
{return GetSender().GetMaxWaitObjectCount();}
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
void GetWaitObjects(WaitObjectContainer &container)
|
|
||||||
{if (m_wasBlocked || !m_buffer.IsEmpty()) AccessSender().GetWaitObjects(container);}
|
|
||||||
|
|
||||||
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
|
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
|
||||||
|
|
||||||
lword TimedFlush(unsigned long maxTime, size_t targetSize = 0);
|
|
||||||
|
|
||||||
void SetMaxBufferSize(size_t maxBufferSize) {m_maxBufferSize = maxBufferSize; m_buffer.SetNodeSize(UnsignedMin(maxBufferSize, 16U*1024U+256U));}
|
void SetMaxBufferSize(size_t maxBufferSize) {m_maxBufferSize = maxBufferSize; m_buffer.SetNodeSize(UnsignedMin(maxBufferSize, 16U*1024U+256U));}
|
||||||
void SetAutoFlushBound(size_t bound) {m_autoFlushBound = bound;}
|
void SetAutoFlushBound(size_t bound) {m_autoFlushBound = bound;}
|
||||||
|
|
||||||
|
|
@ -145,18 +201,25 @@ public:
|
||||||
|
|
||||||
void ClearBuffer() { m_buffer.Clear(); }
|
void ClearBuffer() { m_buffer.Clear(); }
|
||||||
|
|
||||||
|
bool EofPending() const { return m_eofState > EOF_NONE && m_eofState < EOF_DONE; }
|
||||||
|
|
||||||
//! compute the current speed of this sink in bytes per second
|
//! compute the current speed of this sink in bytes per second
|
||||||
float ComputeCurrentSpeed();
|
float ComputeCurrentSpeed();
|
||||||
//! get the maximum observed speed of this sink in bytes per second
|
//! get the maximum observed speed of this sink in bytes per second
|
||||||
float GetMaxObservedSpeed() const {return m_maxObservedSpeed;}
|
float GetMaxObservedSpeed() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
lword DoFlush(unsigned long maxTime, size_t targetSize);
|
||||||
|
|
||||||
virtual NetworkSender & AccessSender() =0;
|
virtual NetworkSender & AccessSender() =0;
|
||||||
const NetworkSender & GetSender() const {return const_cast<NetworkSink *>(this)->AccessSender();}
|
const NetworkSender & GetSender() const {return const_cast<NetworkSink *>(this)->AccessSender();}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum EofState { EOF_NONE, EOF_PENDING_SEND, EOF_PENDING_DELIVERY, EOF_DONE };
|
||||||
|
|
||||||
size_t m_maxBufferSize, m_autoFlushBound;
|
size_t m_maxBufferSize, m_autoFlushBound;
|
||||||
bool m_needSendResult, m_wasBlocked;
|
bool m_needSendResult, m_wasBlocked;
|
||||||
|
EofState m_eofState;
|
||||||
ByteQueue m_buffer;
|
ByteQueue m_buffer;
|
||||||
size_t m_skipBytes;
|
size_t m_skipBytes;
|
||||||
Timer m_speedTimer;
|
Timer m_speedTimer;
|
||||||
|
|
|
||||||
75
socketft.cpp
75
socketft.cpp
|
|
@ -79,6 +79,7 @@ void Socket::CloseSocket()
|
||||||
if (m_s != INVALID_SOCKET)
|
if (m_s != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
|
CancelIo((HANDLE) m_s);
|
||||||
CheckAndHandleError_int("closesocket", closesocket(m_s));
|
CheckAndHandleError_int("closesocket", closesocket(m_s));
|
||||||
#else
|
#else
|
||||||
CheckAndHandleError_int("close", close(m_s));
|
CheckAndHandleError_int("close", close(m_s));
|
||||||
|
|
@ -178,6 +179,12 @@ void Socket::GetSockName(sockaddr *psa, socklen_t *psaLen)
|
||||||
CheckAndHandleError_int("getsockname", getsockname(m_s, psa, psaLen));
|
CheckAndHandleError_int("getsockname", getsockname(m_s, psa, psaLen));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Socket::GetPeerName(sockaddr *psa, socklen_t *psaLen)
|
||||||
|
{
|
||||||
|
assert(m_s != INVALID_SOCKET);
|
||||||
|
CheckAndHandleError_int("getpeername", getpeername(m_s, psa, psaLen));
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int Socket::Send(const byte* buf, size_t bufLen, int flags)
|
unsigned int Socket::Send(const byte* buf, size_t bufLen, int flags)
|
||||||
{
|
{
|
||||||
assert(m_s != INVALID_SOCKET);
|
assert(m_s != INVALID_SOCKET);
|
||||||
|
|
@ -261,7 +268,7 @@ void Socket::StartSockets()
|
||||||
{
|
{
|
||||||
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
WSADATA wsd;
|
WSADATA wsd;
|
||||||
int result = WSAStartup(0x0002, &wsd);
|
int result = WSAStartup(0x0202, &wsd);
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
throw Err(INVALID_SOCKET, "WSAStartup", result);
|
throw Err(INVALID_SOCKET, "WSAStartup", result);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -311,13 +318,20 @@ SocketReceiver::SocketReceiver(Socket &s)
|
||||||
m_overlapped.hEvent = m_event;
|
m_overlapped.hEvent = m_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SocketReceiver::~SocketReceiver()
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
|
CancelIo((HANDLE) m_s.GetSocket());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool SocketReceiver::Receive(byte* buf, size_t bufLen)
|
bool SocketReceiver::Receive(byte* buf, size_t bufLen)
|
||||||
{
|
{
|
||||||
assert(!m_resultPending && !m_eofReceived);
|
assert(!m_resultPending && !m_eofReceived);
|
||||||
|
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
// don't queue too much at once, or we might use up non-paged memory
|
// don't queue too much at once, or we might use up non-paged memory
|
||||||
WSABUF wsabuf = {UnsignedMin(128U*1024U, bufLen), (char *)buf};
|
WSABUF wsabuf = {UnsignedMin((u_long)128*1024, bufLen), (char *)buf};
|
||||||
if (WSARecv(m_s, &wsabuf, 1, &m_lastResult, &flags, &m_overlapped, NULL) == 0)
|
if (WSARecv(m_s, &wsabuf, 1, &m_lastResult, &flags, &m_overlapped, NULL) == 0)
|
||||||
{
|
{
|
||||||
if (m_lastResult == 0)
|
if (m_lastResult == 0)
|
||||||
|
|
@ -340,12 +354,12 @@ bool SocketReceiver::Receive(byte* buf, size_t bufLen)
|
||||||
return !m_resultPending;
|
return !m_resultPending;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketReceiver::GetWaitObjects(WaitObjectContainer &container)
|
void SocketReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
if (m_resultPending)
|
if (m_resultPending)
|
||||||
container.AddHandle(m_event);
|
container.AddHandle(m_event, CallStack("SocketReceiver::GetWaitObjects() - result pending", &callStack));
|
||||||
else if (!m_eofReceived)
|
else if (!m_eofReceived)
|
||||||
container.SetNoWait();
|
container.SetNoWait(CallStack("SocketReceiver::GetWaitObjects() - result ready", &callStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int SocketReceiver::GetReceiveResult()
|
unsigned int SocketReceiver::GetReceiveResult()
|
||||||
|
|
@ -385,11 +399,20 @@ SocketSender::SocketSender(Socket &s)
|
||||||
m_overlapped.hEvent = m_event;
|
m_overlapped.hEvent = m_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SocketSender::~SocketSender()
|
||||||
|
{
|
||||||
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
|
CancelIo((HANDLE) m_s.GetSocket());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void SocketSender::Send(const byte* buf, size_t bufLen)
|
void SocketSender::Send(const byte* buf, size_t bufLen)
|
||||||
{
|
{
|
||||||
|
assert(!m_resultPending);
|
||||||
DWORD written = 0;
|
DWORD written = 0;
|
||||||
// don't queue too much at once, or we might use up non-paged memory
|
// don't queue too much at once, or we might use up non-paged memory
|
||||||
WSABUF wsabuf = {UnsignedMin(128U*1024U, bufLen), (char *)buf};
|
WSABUF wsabuf = {UnsignedMin((u_long)128*1024, bufLen), (char *)buf};
|
||||||
if (WSASend(m_s, &wsabuf, 1, &written, 0, &m_overlapped, NULL) == 0)
|
if (WSASend(m_s, &wsabuf, 1, &written, 0, &m_overlapped, NULL) == 0)
|
||||||
{
|
{
|
||||||
m_resultPending = false;
|
m_resultPending = false;
|
||||||
|
|
@ -404,12 +427,33 @@ void SocketSender::Send(const byte* buf, size_t bufLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketSender::GetWaitObjects(WaitObjectContainer &container)
|
void SocketSender::SendEof()
|
||||||
|
{
|
||||||
|
assert(!m_resultPending);
|
||||||
|
m_s.ShutDown(SD_SEND);
|
||||||
|
m_s.CheckAndHandleError("ResetEvent", ResetEvent(m_event));
|
||||||
|
m_s.CheckAndHandleError_int("WSAEventSelect", WSAEventSelect(m_s, m_event, FD_CLOSE));
|
||||||
|
m_resultPending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketSender::EofSent()
|
||||||
{
|
{
|
||||||
if (m_resultPending)
|
if (m_resultPending)
|
||||||
container.AddHandle(m_event);
|
{
|
||||||
|
WSANETWORKEVENTS events;
|
||||||
|
m_s.CheckAndHandleError_int("WSAEnumNetworkEvents", WSAEnumNetworkEvents(m_s, m_event, &events));
|
||||||
|
m_lastResult = (events.lNetworkEvents & FD_CLOSE) ? 1 : 0;
|
||||||
|
m_resultPending = false;
|
||||||
|
}
|
||||||
|
return m_lastResult != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
|
{
|
||||||
|
if (m_resultPending)
|
||||||
|
container.AddHandle(m_event, CallStack("SocketSender::GetWaitObjects() - result pending", &callStack));
|
||||||
else
|
else
|
||||||
container.SetNoWait();
|
container.SetNoWait(CallStack("SocketSender::GetWaitObjects() - result ready", &callStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int SocketSender::GetSendResult()
|
unsigned int SocketSender::GetSendResult()
|
||||||
|
|
@ -433,10 +477,10 @@ SocketReceiver::SocketReceiver(Socket &s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketReceiver::GetWaitObjects(WaitObjectContainer &container)
|
void SocketReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
if (!m_eofReceived)
|
if (!m_eofReceived)
|
||||||
container.AddReadFd(m_s);
|
container.AddReadFd(m_s, CallStack("SocketReceiver::GetWaitObjects()", &callStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketReceiver::Receive(byte* buf, size_t bufLen)
|
bool SocketReceiver::Receive(byte* buf, size_t bufLen)
|
||||||
|
|
@ -462,14 +506,19 @@ void SocketSender::Send(const byte* buf, size_t bufLen)
|
||||||
m_lastResult = m_s.Send(buf, bufLen);
|
m_lastResult = m_s.Send(buf, bufLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketSender::SendEof()
|
||||||
|
{
|
||||||
|
m_s.ShutDown(SD_SEND);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int SocketSender::GetSendResult()
|
unsigned int SocketSender::GetSendResult()
|
||||||
{
|
{
|
||||||
return m_lastResult;
|
return m_lastResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketSender::GetWaitObjects(WaitObjectContainer &container)
|
void SocketSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
container.AddWriteFd(m_s);
|
container.AddWriteFd(m_s, CallStack("SocketSender::GetWaitObjects()", &callStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
11
socketft.h
11
socketft.h
|
|
@ -77,6 +77,7 @@ public:
|
||||||
bool Connect(const sockaddr* psa, socklen_t saLen);
|
bool Connect(const sockaddr* psa, socklen_t saLen);
|
||||||
bool Accept(Socket& s, sockaddr *psa=NULL, socklen_t *psaLen=NULL);
|
bool Accept(Socket& s, sockaddr *psa=NULL, socklen_t *psaLen=NULL);
|
||||||
void GetSockName(sockaddr *psa, socklen_t *psaLen);
|
void GetSockName(sockaddr *psa, socklen_t *psaLen);
|
||||||
|
void GetPeerName(sockaddr *psa, socklen_t *psaLen);
|
||||||
unsigned int Send(const byte* buf, size_t bufLen, int flags=0);
|
unsigned int Send(const byte* buf, size_t bufLen, int flags=0);
|
||||||
unsigned int Receive(byte* buf, size_t bufLen, int flags=0);
|
unsigned int Receive(byte* buf, size_t bufLen, int flags=0);
|
||||||
void ShutDown(int how = SD_SEND);
|
void ShutDown(int how = SD_SEND);
|
||||||
|
|
@ -128,6 +129,7 @@ public:
|
||||||
#ifdef USE_BERKELEY_STYLE_SOCKETS
|
#ifdef USE_BERKELEY_STYLE_SOCKETS
|
||||||
bool MustWaitToReceive() {return true;}
|
bool MustWaitToReceive() {return true;}
|
||||||
#else
|
#else
|
||||||
|
~SocketReceiver();
|
||||||
bool MustWaitForResult() {return true;}
|
bool MustWaitForResult() {return true;}
|
||||||
#endif
|
#endif
|
||||||
bool Receive(byte* buf, size_t bufLen);
|
bool Receive(byte* buf, size_t bufLen);
|
||||||
|
|
@ -135,7 +137,7 @@ public:
|
||||||
bool EofReceived() const {return m_eofReceived;}
|
bool EofReceived() const {return m_eofReceived;}
|
||||||
|
|
||||||
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
||||||
void GetWaitObjects(WaitObjectContainer &container);
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Socket &m_s;
|
Socket &m_s;
|
||||||
|
|
@ -159,14 +161,17 @@ public:
|
||||||
#ifdef USE_BERKELEY_STYLE_SOCKETS
|
#ifdef USE_BERKELEY_STYLE_SOCKETS
|
||||||
bool MustWaitToSend() {return true;}
|
bool MustWaitToSend() {return true;}
|
||||||
#else
|
#else
|
||||||
|
~SocketSender();
|
||||||
bool MustWaitForResult() {return true;}
|
bool MustWaitForResult() {return true;}
|
||||||
|
bool MustWaitForEof() { return true; }
|
||||||
|
bool EofSent();
|
||||||
#endif
|
#endif
|
||||||
void Send(const byte* buf, size_t bufLen);
|
void Send(const byte* buf, size_t bufLen);
|
||||||
unsigned int GetSendResult();
|
unsigned int GetSendResult();
|
||||||
void SendEof() {m_s.ShutDown(SD_SEND);}
|
void SendEof();
|
||||||
|
|
||||||
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
||||||
void GetWaitObjects(WaitObjectContainer &container);
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Socket &m_s;
|
Socket &m_s;
|
||||||
|
|
|
||||||
6
test.cpp
6
test.cpp
|
|
@ -192,7 +192,7 @@ int __cdecl main(int argc, char *argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int macPos = unsigned int(found-buf.begin());
|
unsigned int macPos = (unsigned int)(found-buf.begin());
|
||||||
member_ptr<MessageAuthenticationCode> pMac(NewIntegrityCheckingMAC());
|
member_ptr<MessageAuthenticationCode> pMac(NewIntegrityCheckingMAC());
|
||||||
pMac->Update(buf.begin(), macPos);
|
pMac->Update(buf.begin(), macPos);
|
||||||
pMac->Update(buf.begin() + macPos + sizeof(dummyMac), fileSize - sizeof(dummyMac) - macPos);
|
pMac->Update(buf.begin() + macPos + sizeof(dummyMac), fileSize - sizeof(dummyMac) - macPos);
|
||||||
|
|
@ -683,8 +683,8 @@ void ForwardTcpPort(const char *sourcePortName, const char *destinationHost, con
|
||||||
{
|
{
|
||||||
waitObjects.Clear();
|
waitObjects.Clear();
|
||||||
|
|
||||||
out.GetWaitObjects(waitObjects);
|
out.GetWaitObjects(waitObjects, CallStack("ForwardTcpPort - out", NULL));
|
||||||
in.GetWaitObjects(waitObjects);
|
in.GetWaitObjects(waitObjects, CallStack("ForwardTcpPort - in", NULL));
|
||||||
|
|
||||||
waitObjects.Wait(INFINITE_TIME);
|
waitObjects.Wait(INFINITE_TIME);
|
||||||
|
|
||||||
|
|
|
||||||
167
wait.cpp
167
wait.cpp
|
|
@ -13,12 +13,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TRACE_WAIT 0
|
|
||||||
|
|
||||||
#if TRACE_WAIT
|
|
||||||
#include "hrtimer.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
unsigned int WaitObjectContainer::MaxWaitObjects()
|
unsigned int WaitObjectContainer::MaxWaitObjects()
|
||||||
|
|
@ -30,12 +24,12 @@ unsigned int WaitObjectContainer::MaxWaitObjects()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitObjectContainer::WaitObjectContainer()
|
WaitObjectContainer::WaitObjectContainer(WaitObjectsTracer* tracer)
|
||||||
#if CRYPTOPP_DETECT_NO_WAIT
|
: m_tracer(tracer), m_eventTimer(Timer::MILLISECONDS)
|
||||||
: m_sameResultCount(0), m_timer(Timer::MILLISECONDS)
|
, m_sameResultCount(0), m_noWaitTimer(Timer::MILLISECONDS)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
m_eventTimer.StartTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitObjectContainer::Clear()
|
void WaitObjectContainer::Clear()
|
||||||
|
|
@ -48,21 +42,57 @@ void WaitObjectContainer::Clear()
|
||||||
FD_ZERO(&m_writefds);
|
FD_ZERO(&m_writefds);
|
||||||
#endif
|
#endif
|
||||||
m_noWait = false;
|
m_noWait = false;
|
||||||
|
m_firstEventTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitObjectContainer::SetNoWait()
|
inline void WaitObjectContainer::SetLastResult(LastResultType result)
|
||||||
{
|
{
|
||||||
#if CRYPTOPP_DETECT_NO_WAIT
|
if (result == m_lastResult)
|
||||||
if (-1 == m_lastResult && m_timer.ElapsedTime() > 1000)
|
m_sameResultCount++;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (m_sameResultCount > m_timer.ElapsedTime())
|
m_lastResult = result;
|
||||||
try {throw 0;} catch (...) {} // possible no-wait loop, break in debugger
|
m_sameResultCount = 0;
|
||||||
m_timer.StartTimer();
|
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
void WaitObjectContainer::DetectNoWait(LastResultType result, CallStack const& callStack)
|
||||||
|
{
|
||||||
|
if (result == m_lastResult && m_noWaitTimer.ElapsedTime() > 1000)
|
||||||
|
{
|
||||||
|
if (m_sameResultCount > m_noWaitTimer.ElapsedTime())
|
||||||
|
{
|
||||||
|
if (m_tracer)
|
||||||
|
{
|
||||||
|
std::string desc = "No wait loop detected - m_lastResult: ";
|
||||||
|
desc.append(IntToString(m_lastResult)).append(", call stack:");
|
||||||
|
for (CallStack const* cs = &callStack; cs; cs = cs->Prev())
|
||||||
|
desc.append("\n- ").append(cs->Format());
|
||||||
|
m_tracer->TraceNoWaitLoop(desc);
|
||||||
|
}
|
||||||
|
try { throw 0; } catch (...) {} // help debugger break
|
||||||
|
}
|
||||||
|
|
||||||
|
m_noWaitTimer.StartTimer();
|
||||||
|
m_sameResultCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitObjectContainer::SetNoWait(CallStack const& callStack)
|
||||||
|
{
|
||||||
|
DetectNoWait(LASTRESULT_NOWAIT, CallStack("WaitObjectContainer::SetNoWait()", &callStack));
|
||||||
m_noWait = true;
|
m_noWait = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaitObjectContainer::ScheduleEvent(double milliseconds, CallStack const& callStack)
|
||||||
|
{
|
||||||
|
if (milliseconds <= 3)
|
||||||
|
DetectNoWait(LASTRESULT_SCHEDULED, CallStack("WaitObjectContainer::ScheduleEvent()", &callStack));
|
||||||
|
double thisEventTime = m_eventTimer.ElapsedTimeAsDouble() + milliseconds;
|
||||||
|
if (!m_firstEventTime || thisEventTime < m_firstEventTime)
|
||||||
|
m_firstEventTime = thisEventTime;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
|
|
||||||
struct WaitingThreadData
|
struct WaitingThreadData
|
||||||
|
|
@ -106,16 +136,9 @@ WaitObjectContainer::~WaitObjectContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WaitObjectContainer::AddHandle(HANDLE handle)
|
void WaitObjectContainer::AddHandle(HANDLE handle, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
#if CRYPTOPP_DETECT_NO_WAIT
|
DetectNoWait(m_handles.size(), CallStack("WaitObjectContainer::AddHandle()", &callStack));
|
||||||
if (m_handles.size() == m_lastResult && m_timer.ElapsedTime() > 1000)
|
|
||||||
{
|
|
||||||
if (m_sameResultCount > m_timer.ElapsedTime())
|
|
||||||
try {throw 0;} catch (...) {} // possible no-wait loop, break in debugger
|
|
||||||
m_timer.StartTimer();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
m_handles.push_back(handle);
|
m_handles.push_back(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +180,7 @@ DWORD WINAPI WaitingThread(LPVOID lParam)
|
||||||
|
|
||||||
void WaitObjectContainer::CreateThreads(unsigned int count)
|
void WaitObjectContainer::CreateThreads(unsigned int count)
|
||||||
{
|
{
|
||||||
unsigned int currentCount = (unsigned int)m_threads.size();
|
size_t currentCount = m_threads.size();
|
||||||
if (currentCount == 0)
|
if (currentCount == 0)
|
||||||
{
|
{
|
||||||
m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
@ -167,7 +190,7 @@ void WaitObjectContainer::CreateThreads(unsigned int count)
|
||||||
if (currentCount < count)
|
if (currentCount < count)
|
||||||
{
|
{
|
||||||
m_threads.resize(count);
|
m_threads.resize(count);
|
||||||
for (unsigned int i=currentCount; i<count; i++)
|
for (size_t i=currentCount; i<count; i++)
|
||||||
{
|
{
|
||||||
m_threads[i] = new WaitingThreadData;
|
m_threads[i] = new WaitingThreadData;
|
||||||
WaitingThreadData &thread = *m_threads[i];
|
WaitingThreadData &thread = *m_threads[i];
|
||||||
|
|
@ -182,20 +205,33 @@ void WaitObjectContainer::CreateThreads(unsigned int count)
|
||||||
|
|
||||||
bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
||||||
{
|
{
|
||||||
if (m_noWait || m_handles.empty())
|
if (m_noWait || (m_handles.empty() && !m_firstEventTime))
|
||||||
{
|
{
|
||||||
#if CRYPTOPP_DETECT_NO_WAIT
|
SetLastResult(LASTRESULT_NOWAIT);
|
||||||
if (-1 == m_lastResult)
|
|
||||||
m_sameResultCount++;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_lastResult = -1;
|
|
||||||
m_sameResultCount = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
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)
|
if (m_handles.size() > MAXIMUM_WAIT_OBJECTS)
|
||||||
{
|
{
|
||||||
// too many wait objects for a single WaitForMultipleObjects call, so use multiple threads
|
// too many wait objects for a single WaitForMultipleObjects call, so use multiple threads
|
||||||
|
|
@ -230,11 +266,14 @@ bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
||||||
if (error == S_OK)
|
if (error == S_OK)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(error));
|
throw Err("WaitObjectContainer: WaitForMultipleObjects in thread failed with error " + IntToString(error));
|
||||||
}
|
}
|
||||||
SetEvent(m_stopWaiting);
|
SetEvent(m_stopWaiting);
|
||||||
if (result == WAIT_TIMEOUT)
|
if (result == WAIT_TIMEOUT)
|
||||||
return false;
|
{
|
||||||
|
SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
|
||||||
|
return timeoutIsScheduledEvent;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw Err("WaitObjectContainer: WaitForSingleObject failed with error " + IntToString(::GetLastError()));
|
throw Err("WaitObjectContainer: WaitForSingleObject failed with error " + IntToString(::GetLastError()));
|
||||||
}
|
}
|
||||||
|
|
@ -256,7 +295,6 @@ bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
||||||
#endif
|
#endif
|
||||||
if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
|
if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
|
||||||
{
|
{
|
||||||
#if CRYPTOPP_DETECT_NO_WAIT
|
|
||||||
if (result == m_lastResult)
|
if (result == m_lastResult)
|
||||||
m_sameResultCount++;
|
m_sameResultCount++;
|
||||||
else
|
else
|
||||||
|
|
@ -264,25 +302,27 @@ bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
||||||
m_lastResult = result;
|
m_lastResult = result;
|
||||||
m_sameResultCount = 0;
|
m_sameResultCount = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (result == WAIT_TIMEOUT)
|
else if (result == WAIT_TIMEOUT)
|
||||||
return false;
|
{
|
||||||
|
SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
|
||||||
|
return timeoutIsScheduledEvent;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(::GetLastError()));
|
throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(::GetLastError()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else // #ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
|
|
||||||
void WaitObjectContainer::AddReadFd(int fd)
|
void WaitObjectContainer::AddReadFd(int fd, CallStack const& callStack) // TODO: do something with callStack
|
||||||
{
|
{
|
||||||
FD_SET(fd, &m_readfds);
|
FD_SET(fd, &m_readfds);
|
||||||
m_maxFd = STDMAX(m_maxFd, fd);
|
m_maxFd = STDMAX(m_maxFd, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitObjectContainer::AddWriteFd(int fd)
|
void WaitObjectContainer::AddWriteFd(int fd, CallStack const& callStack) // TODO: do something with callStack
|
||||||
{
|
{
|
||||||
FD_SET(fd, &m_writefds);
|
FD_SET(fd, &m_writefds);
|
||||||
m_maxFd = STDMAX(m_maxFd, fd);
|
m_maxFd = STDMAX(m_maxFd, fd);
|
||||||
|
|
@ -290,9 +330,21 @@ void WaitObjectContainer::AddWriteFd(int fd)
|
||||||
|
|
||||||
bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
||||||
{
|
{
|
||||||
if (m_noWait || m_maxFd == 0)
|
if (m_noWait || (!m_maxFd && !m_firstEventTime))
|
||||||
return true;
|
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;
|
timeval tv, *timeout;
|
||||||
|
|
||||||
if (milliseconds == INFINITE_TIME)
|
if (milliseconds == INFINITE_TIME)
|
||||||
|
|
@ -309,7 +361,7 @@ bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
return true;
|
return true;
|
||||||
else if (result == 0)
|
else if (result == 0)
|
||||||
return false;
|
return timeoutIsScheduledEvent;
|
||||||
else
|
else
|
||||||
throw Err("WaitObjectContainer: select failed with error " + errno);
|
throw Err("WaitObjectContainer: select failed with error " + errno);
|
||||||
}
|
}
|
||||||
|
|
@ -318,10 +370,25 @@ bool WaitObjectContainer::Wait(unsigned long milliseconds)
|
||||||
|
|
||||||
// ********************************************************
|
// ********************************************************
|
||||||
|
|
||||||
bool Waitable::Wait(unsigned long milliseconds)
|
std::string CallStack::Format() const
|
||||||
|
{
|
||||||
|
return m_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CallStackWithNr::Format() const
|
||||||
|
{
|
||||||
|
return std::string(m_info) + " / nr: " + IntToString(m_nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CallStackWithStr::Format() const
|
||||||
|
{
|
||||||
|
return std::string(m_info) + " / " + std::string(m_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Waitable::Wait(unsigned long milliseconds, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
WaitObjectContainer container;
|
WaitObjectContainer container;
|
||||||
GetWaitObjects(container);
|
GetWaitObjects(container, callStack); // reduce clutter by not adding this func to stack
|
||||||
return container.Wait(milliseconds);
|
return container.Wait(milliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
160
wait.h
160
wait.h
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#ifdef SOCKETS_AVAILABLE
|
#ifdef SOCKETS_AVAILABLE
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
#include "cryptlib.h"
|
#include "cryptlib.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -14,22 +15,135 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define CRYPTOPP_DETECT_NO_WAIT 0
|
|
||||||
#else
|
|
||||||
#define CRYPTOPP_DETECT_NO_WAIT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CRYPTOPP_DETECT_NO_WAIT
|
|
||||||
#include "hrtimer.h"
|
#include "hrtimer.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
class Tracer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Tracer(unsigned int level) : m_level(level) {}
|
||||||
|
virtual ~Tracer() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//! Override this in your most-derived tracer to do the actual tracing.
|
||||||
|
virtual void Trace(unsigned int n, std::string const& s) = 0;
|
||||||
|
|
||||||
|
/*! By default, tracers will decide which trace messages to trace according to a trace level
|
||||||
|
mechanism. If your most-derived tracer uses a different mechanism, override this to
|
||||||
|
return false. If this method returns false, the default TraceXxxx(void) methods will all
|
||||||
|
return 0 and must be overridden explicitly by your tracer for trace messages you want. */
|
||||||
|
virtual bool UsingDefaults() const { return true; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
unsigned int m_level;
|
||||||
|
|
||||||
|
void TraceIf(unsigned int n, std::string const&s)
|
||||||
|
{ if (n) Trace(n, s); }
|
||||||
|
|
||||||
|
/*! Returns nr if, according to the default log settings mechanism (using log levels),
|
||||||
|
the message should be traced. Returns 0 if the default trace level mechanism is not
|
||||||
|
in use, or if it is in use but the event should not be traced. Provided as a utility
|
||||||
|
method for easier and shorter coding of default TraceXxxx(void) implementations. */
|
||||||
|
unsigned int Tracing(unsigned int nr, unsigned int minLevel) const
|
||||||
|
{ return (UsingDefaults() && m_level >= minLevel) ? nr : 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Your Tracer-derived class should inherit as virtual public from Tracer or another
|
||||||
|
// Tracer-derived class, and should pass the log level in its constructor. You can use the
|
||||||
|
// following methods to begin and end your Tracer definition.
|
||||||
|
|
||||||
|
// This constructor macro initializes Tracer directly even if not derived directly from it;
|
||||||
|
// this is intended, virtual base classes are always initialized by the most derived class.
|
||||||
|
#define CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED) \
|
||||||
|
public: DERIVED(unsigned int level = 0) : Tracer(level) {}
|
||||||
|
|
||||||
|
#define CRYPTOPP_BEGIN_TRACER_CLASS_1(DERIVED, BASE1) \
|
||||||
|
class DERIVED : virtual public BASE1 { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED)
|
||||||
|
|
||||||
|
#define CRYPTOPP_BEGIN_TRACER_CLASS_2(DERIVED, BASE1, BASE2) \
|
||||||
|
class DERIVED : virtual public BASE1, virtual public BASE2 { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED)
|
||||||
|
|
||||||
|
#define CRYPTOPP_END_TRACER_CLASS };
|
||||||
|
|
||||||
|
// In your Tracer-derived class, you should define a globally unique event number for each
|
||||||
|
// new event defined. This can be done using the following macros.
|
||||||
|
|
||||||
|
#define CRYPTOPP_BEGIN_TRACER_EVENTS(UNIQUENR) enum { EVENTBASE = UNIQUENR,
|
||||||
|
#define CRYPTOPP_TRACER_EVENT(EVENTNAME) EventNr_##EVENTNAME,
|
||||||
|
#define CRYPTOPP_END_TRACER_EVENTS };
|
||||||
|
|
||||||
|
// In your own Tracer-derived class, you must define two methods per new trace event type:
|
||||||
|
// - unsigned int TraceXxxx() const
|
||||||
|
// Your default implementation of this method should return the event number if according
|
||||||
|
// to the default trace level system the event should be traced, or 0 if it should not.
|
||||||
|
// - void TraceXxxx(string const& s)
|
||||||
|
// This method should call TraceIf(TraceXxxx(), s); to do the tracing.
|
||||||
|
// For your convenience, a macro to define these two types of methods are defined below.
|
||||||
|
// If you use this macro, you should also use the TRACER_EVENTS macros above to associate
|
||||||
|
// event names with numbers.
|
||||||
|
|
||||||
|
#define CRYPTOPP_TRACER_EVENT_METHODS(EVENTNAME, LOGLEVEL) \
|
||||||
|
virtual unsigned int Trace##EVENTNAME() const { return Tracing(EventNr_##EVENTNAME, LOGLEVEL); } \
|
||||||
|
virtual void Trace##EVENTNAME(std::string const& s) { TraceIf(Trace##EVENTNAME(), s); }
|
||||||
|
|
||||||
|
|
||||||
|
/*! A simple unidirectional linked list with m_prev == 0 to indicate the final entry.
|
||||||
|
The aim of this implementation is to provide a very lightweight and practical
|
||||||
|
tracing mechanism with a low performance impact. Functions and methods supporting
|
||||||
|
this call-stack mechanism would take a parameter of the form "CallStack const& callStack",
|
||||||
|
and would pass this parameter to subsequent functions they call using the construct:
|
||||||
|
|
||||||
|
SubFunc(arg1, arg2, CallStack("my func at place such and such", &callStack));
|
||||||
|
|
||||||
|
The advantage of this approach is that it is easy to use and should be very efficient,
|
||||||
|
involving no allocation from the heap, just a linked list of stack objects containing
|
||||||
|
pointers to static ASCIIZ strings (or possibly additional but simple data if derived). */
|
||||||
|
class CallStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CallStack(char const* i, CallStack const* p) : m_info(i), m_prev(p) {}
|
||||||
|
CallStack const* Prev() const { return m_prev; }
|
||||||
|
virtual std::string Format() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
char const* m_info;
|
||||||
|
CallStack const* m_prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! An extended CallStack entry type with an additional numeric parameter. */
|
||||||
|
class CallStackWithNr : public CallStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CallStackWithNr(char const* i, word32 n, CallStack const* p) : CallStack(i, p), m_nr(n) {}
|
||||||
|
std::string Format() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
word32 m_nr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! An extended CallStack entry type with an additional string parameter. */
|
||||||
|
class CallStackWithStr : public CallStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CallStackWithStr(char const* i, char const* z, CallStack const* p) : CallStack(i, p), m_z(z) {}
|
||||||
|
std::string Format() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
char const* m_z;
|
||||||
|
};
|
||||||
|
|
||||||
|
CRYPTOPP_BEGIN_TRACER_CLASS_1(WaitObjectsTracer, Tracer)
|
||||||
|
CRYPTOPP_BEGIN_TRACER_EVENTS(0x48752841)
|
||||||
|
CRYPTOPP_TRACER_EVENT(NoWaitLoop)
|
||||||
|
CRYPTOPP_END_TRACER_EVENTS
|
||||||
|
CRYPTOPP_TRACER_EVENT_METHODS(NoWaitLoop, 1)
|
||||||
|
CRYPTOPP_END_TRACER_CLASS
|
||||||
|
|
||||||
struct WaitingThreadData;
|
struct WaitingThreadData;
|
||||||
|
|
||||||
//! container of wait objects
|
//! container of wait objects
|
||||||
class WaitObjectContainer
|
class WaitObjectContainer : public NotCopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//! exception thrown by WaitObjectContainer
|
//! exception thrown by WaitObjectContainer
|
||||||
|
|
@ -41,21 +155,25 @@ public:
|
||||||
|
|
||||||
static unsigned int MaxWaitObjects();
|
static unsigned int MaxWaitObjects();
|
||||||
|
|
||||||
WaitObjectContainer();
|
WaitObjectContainer(WaitObjectsTracer* tracer = 0);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
void SetNoWait();
|
void SetNoWait(CallStack const& callStack);
|
||||||
|
void ScheduleEvent(double milliseconds, CallStack const& callStack);
|
||||||
|
// returns false if timed out
|
||||||
bool Wait(unsigned long milliseconds);
|
bool Wait(unsigned long milliseconds);
|
||||||
|
|
||||||
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
~WaitObjectContainer();
|
~WaitObjectContainer();
|
||||||
void AddHandle(HANDLE handle);
|
void AddHandle(HANDLE handle, CallStack const& callStack);
|
||||||
#else
|
#else
|
||||||
void AddReadFd(int fd);
|
void AddReadFd(int fd, CallStack const& callStack);
|
||||||
void AddWriteFd(int fd);
|
void AddWriteFd(int fd, CallStack const& callStack);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
WaitObjectsTracer* m_tracer;
|
||||||
|
|
||||||
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
void CreateThreads(unsigned int count);
|
void CreateThreads(unsigned int count);
|
||||||
std::vector<HANDLE> m_handles;
|
std::vector<HANDLE> m_handles;
|
||||||
|
|
@ -67,16 +185,20 @@ private:
|
||||||
int m_maxFd;
|
int m_maxFd;
|
||||||
#endif
|
#endif
|
||||||
bool m_noWait;
|
bool m_noWait;
|
||||||
|
double m_firstEventTime;
|
||||||
|
Timer m_eventTimer;
|
||||||
|
|
||||||
#if CRYPTOPP_DETECT_NO_WAIT
|
|
||||||
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
#ifdef USE_WINDOWS_STYLE_SOCKETS
|
||||||
DWORD m_lastResult;
|
typedef size_t LastResultType;
|
||||||
#else
|
#else
|
||||||
int m_lastResult;
|
typedef int LastResultType;
|
||||||
#endif
|
#endif
|
||||||
|
enum { LASTRESULT_NOWAIT = -1, LASTRESULT_SCHEDULED = -2, LASTRESULT_TIMEOUT = -3 };
|
||||||
|
LastResultType m_lastResult;
|
||||||
unsigned int m_sameResultCount;
|
unsigned int m_sameResultCount;
|
||||||
Timer m_timer;
|
Timer m_noWaitTimer;
|
||||||
#endif
|
void SetLastResult(LastResultType result);
|
||||||
|
void DetectNoWait(LastResultType result, CallStack const& callStack);
|
||||||
};
|
};
|
||||||
|
|
||||||
NAMESPACE_END
|
NAMESPACE_END
|
||||||
|
|
|
||||||
16
winpipes.cpp
16
winpipes.cpp
|
|
@ -92,7 +92,7 @@ bool WindowsPipeReceiver::Receive(byte* buf, size_t bufLen)
|
||||||
|
|
||||||
HANDLE h = GetHandle();
|
HANDLE h = GetHandle();
|
||||||
// don't queue too much at once, or we might use up non-paged memory
|
// don't queue too much at once, or we might use up non-paged memory
|
||||||
if (ReadFile(h, buf, UnsignedMin(128U*1024U, bufLen), &m_lastResult, &m_overlapped))
|
if (ReadFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &m_lastResult, &m_overlapped))
|
||||||
{
|
{
|
||||||
if (m_lastResult == 0)
|
if (m_lastResult == 0)
|
||||||
m_eofReceived = true;
|
m_eofReceived = true;
|
||||||
|
|
@ -115,12 +115,12 @@ bool WindowsPipeReceiver::Receive(byte* buf, size_t bufLen)
|
||||||
return !m_resultPending;
|
return !m_resultPending;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowsPipeReceiver::GetWaitObjects(WaitObjectContainer &container)
|
void WindowsPipeReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
if (m_resultPending)
|
if (m_resultPending)
|
||||||
container.AddHandle(m_event);
|
container.AddHandle(m_event, CallStack("WindowsPipeReceiver::GetWaitObjects() - result pending", &callStack));
|
||||||
else if (!m_eofReceived)
|
else if (!m_eofReceived)
|
||||||
container.SetNoWait();
|
container.SetNoWait(CallStack("WindowsPipeReceiver::GetWaitObjects() - result ready", &callStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int WindowsPipeReceiver::GetReceiveResult()
|
unsigned int WindowsPipeReceiver::GetReceiveResult()
|
||||||
|
|
@ -166,7 +166,7 @@ void WindowsPipeSender::Send(const byte* buf, size_t bufLen)
|
||||||
DWORD written = 0;
|
DWORD written = 0;
|
||||||
HANDLE h = GetHandle();
|
HANDLE h = GetHandle();
|
||||||
// don't queue too much at once, or we might use up non-paged memory
|
// don't queue too much at once, or we might use up non-paged memory
|
||||||
if (WriteFile(h, buf, UnsignedMin(128U*1024U, bufLen), &written, &m_overlapped))
|
if (WriteFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &written, &m_overlapped))
|
||||||
{
|
{
|
||||||
m_resultPending = false;
|
m_resultPending = false;
|
||||||
m_lastResult = written;
|
m_lastResult = written;
|
||||||
|
|
@ -180,12 +180,12 @@ void WindowsPipeSender::Send(const byte* buf, size_t bufLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowsPipeSender::GetWaitObjects(WaitObjectContainer &container)
|
void WindowsPipeSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
|
||||||
{
|
{
|
||||||
if (m_resultPending)
|
if (m_resultPending)
|
||||||
container.AddHandle(m_event);
|
container.AddHandle(m_event, CallStack("WindowsPipeSender::GetWaitObjects() - result pending", &callStack));
|
||||||
else
|
else
|
||||||
container.SetNoWait();
|
container.SetNoWait(CallStack("WindowsPipeSender::GetWaitObjects() - result ready", &callStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int WindowsPipeSender::GetSendResult()
|
unsigned int WindowsPipeSender::GetSendResult()
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ public:
|
||||||
bool EofReceived() const {return m_eofReceived;}
|
bool EofReceived() const {return m_eofReceived;}
|
||||||
|
|
||||||
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
||||||
void GetWaitObjects(WaitObjectContainer &container);
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WindowsHandle m_event;
|
WindowsHandle m_event;
|
||||||
|
|
@ -88,10 +88,11 @@ public:
|
||||||
bool MustWaitForResult() {return true;}
|
bool MustWaitForResult() {return true;}
|
||||||
void Send(const byte* buf, size_t bufLen);
|
void Send(const byte* buf, size_t bufLen);
|
||||||
unsigned int GetSendResult();
|
unsigned int GetSendResult();
|
||||||
|
bool MustWaitForEof() { return false; }
|
||||||
void SendEof() {}
|
void SendEof() {}
|
||||||
|
|
||||||
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
unsigned int GetMaxWaitObjectCount() const {return 1;}
|
||||||
void GetWaitObjects(WaitObjectContainer &container);
|
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WindowsHandle m_event;
|
WindowsHandle m_event;
|
||||||
|
|
|
||||||
|
|
@ -383,7 +383,13 @@ unsigned int Deflator::LongestMatch(unsigned int &bestMatch) const
|
||||||
if (scan[bestLength-1] == match[bestLength-1] && scan[bestLength] == match[bestLength] && scan[0] == match[0] && scan[1] == match[1])
|
if (scan[bestLength-1] == match[bestLength-1] && scan[bestLength] == match[bestLength] && scan[0] == match[0] && scan[1] == match[1])
|
||||||
{
|
{
|
||||||
assert(scan[2] == match[2]);
|
assert(scan[2] == match[2]);
|
||||||
unsigned int len = (unsigned int)(stdext::unchecked_mismatch(scan+3, scanEnd, match+3).first - scan);
|
unsigned int len = (unsigned int)(
|
||||||
|
#ifdef _STDEXT_BEGIN
|
||||||
|
stdext::unchecked_mismatch
|
||||||
|
#else
|
||||||
|
std::mismatch
|
||||||
|
#endif
|
||||||
|
(scan+3, scanEnd, match+3).first - scan);
|
||||||
assert(len != bestLength);
|
assert(len != bestLength);
|
||||||
if (len > bestLength)
|
if (len > bestLength)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ void Inflator::OutputString(const byte *string, size_t length)
|
||||||
{
|
{
|
||||||
while (length)
|
while (length)
|
||||||
{
|
{
|
||||||
size_t len = STDMIN(length, m_window.size() - m_current);
|
size_t len = UnsignedMin(length, m_window.size() - m_current);
|
||||||
memcpy(m_window + m_current, string, len);
|
memcpy(m_window + m_current, string, len);
|
||||||
m_current += len;
|
m_current += len;
|
||||||
if (m_current == m_window.size())
|
if (m_current == m_window.size())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue