ext-cryptopp/network.cpp

283 lines
7.8 KiB
C++
Raw Normal View History

2002-10-04 17:31:41 +00:00
// network.cpp - written and placed in the public domain by Wei Dai
#include "pch.h"
#include "network.h"
2003-06-06 02:34:03 +00:00
#include "wait.h"
2002-10-04 17:31:41 +00:00
2003-06-19 17:09:07 +00:00
#define CRYPTOPP_TRACE_NETWORK 0
2002-10-04 17:31:41 +00:00
NAMESPACE_BEGIN(CryptoPP)
unsigned int NonblockingSource::PumpMessages2(unsigned int &messageCount, bool blocking)
{
if (messageCount == 0)
return 0;
unsigned long byteCount = ULONG_MAX;
messageCount = 0;
RETURN_IF_NONZERO(Pump2(byteCount, blocking));
if (!m_messageEndSent && SourceExhausted())
{
RETURN_IF_NONZERO(AttachedTransformation()->Put2(NULL, 0, GetAutoSignalPropagation(), true));
m_messageEndSent = true;
messageCount = 1;
}
return 0;
}
bool NonblockingSink::IsolatedFlush(bool hardFlush, bool blocking)
{
TimedFlush(blocking ? INFINITE_TIME : 0);
return hardFlush && !!GetCurrentBufferSize();
}
// *************************************************************
#ifdef HIGHRES_TIMER_AVAILABLE
NetworkSource::NetworkSource(BufferedTransformation *attachment)
2003-06-06 02:34:03 +00:00
: NonblockingSource(attachment), m_buf(1024*16)
, m_waitingForResult(false), m_outputBlocked(false)
, m_dataBegin(0), m_dataEnd(0)
2002-10-04 17:31:41 +00:00
{
}
2003-06-06 02:34:03 +00:00
void NetworkSource::GetWaitObjects(WaitObjectContainer &container)
{
if (!m_outputBlocked)
{
if (m_dataBegin == m_dataEnd)
AccessReceiver().GetWaitObjects(container);
else
container.SetNoWait();
}
AttachedTransformation()->GetWaitObjects(container);
}
2002-10-04 17:31:41 +00:00
unsigned int NetworkSource::GeneralPump2(unsigned long &byteCount, bool blockingOutput, unsigned long maxTime, bool checkDelimiter, byte delimiter)
{
NetworkReceiver &receiver = AccessReceiver();
unsigned long maxSize = byteCount;
byteCount = 0;
bool forever = maxTime == INFINITE_TIME;
Timer timer(Timer::MILLISECONDS, forever);
BufferedTransformation *t = AttachedTransformation();
2003-06-06 02:34:03 +00:00
if (m_outputBlocked)
2002-10-04 17:31:41 +00:00
goto DoOutput;
while (true)
{
2003-06-06 02:34:03 +00:00
if (m_dataBegin == m_dataEnd)
2002-10-04 17:31:41 +00:00
{
2003-06-06 02:34:03 +00:00
if (receiver.EofReceived())
break;
if (m_waitingForResult)
2002-10-04 17:31:41 +00:00
{
2003-06-06 02:34:03 +00:00
if (receiver.MustWaitForResult() && !receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
2002-10-04 17:31:41 +00:00
break;
2003-06-06 02:34:03 +00:00
unsigned int recvResult = receiver.GetReceiveResult();
2003-06-19 17:09:07 +00:00
#if CRYPTOPP_TRACE_NETWORK
OutputDebugString((IntToString((unsigned int)this) + ": Received " + IntToString(recvResult) + " bytes\n").c_str());
#endif
2003-06-06 02:34:03 +00:00
m_dataEnd += recvResult;
m_waitingForResult = false;
if (!receiver.MustWaitToReceive() && !receiver.EofReceived() && m_dataEnd != m_buf.size())
goto ReceiveNoWait;
2002-10-04 17:31:41 +00:00
}
2003-06-06 02:34:03 +00:00
else
{
m_dataEnd = m_dataBegin = 0;
2002-10-04 17:31:41 +00:00
2003-06-06 02:34:03 +00:00
if (receiver.MustWaitToReceive())
{
if (!receiver.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
break;
2002-10-04 17:31:41 +00:00
2003-06-06 02:34:03 +00:00
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
2003-06-19 17:09:07 +00:00
#if CRYPTOPP_TRACE_NETWORK
OutputDebugString((IntToString((unsigned int)this) + ": Receiving " + IntToString(m_buf.size()-m_dataEnd) + " bytes\n").c_str());
#endif
2003-06-06 02:34:03 +00:00
while (receiver.Receive(m_buf+m_dataEnd, m_buf.size()-m_dataEnd))
{
unsigned int recvResult = receiver.GetReceiveResult();
2003-06-19 17:09:07 +00:00
#if CRYPTOPP_TRACE_NETWORK
OutputDebugString((IntToString((unsigned int)this) + ": Received " + IntToString(recvResult) + " bytes\n").c_str());
#endif
2003-06-06 02:34:03 +00:00
m_dataEnd += recvResult;
2003-06-19 17:09:07 +00:00
if (receiver.EofReceived() || m_dataEnd > m_buf.size() /2)
2003-06-06 02:34:03 +00:00
{
m_waitingForResult = false;
break;
}
}
}
}
2002-10-04 17:31:41 +00:00
}
else
{
2003-06-06 02:34:03 +00:00
m_putSize = STDMIN((unsigned long)m_dataEnd-m_dataBegin, maxSize-byteCount);
2002-10-04 17:31:41 +00:00
if (checkDelimiter)
2003-06-06 02:34:03 +00:00
m_putSize = std::find(m_buf+m_dataBegin, m_buf+m_dataBegin+m_putSize, delimiter) - (m_buf+m_dataBegin);
2002-10-04 17:31:41 +00:00
DoOutput:
2003-06-06 02:34:03 +00:00
unsigned int result = t->PutModifiable2(m_buf+m_dataBegin, m_putSize, 0, forever || blockingOutput);
2002-10-04 17:31:41 +00:00
if (result)
{
2003-06-06 02:34:03 +00:00
if (t->Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
2002-10-04 17:31:41 +00:00
goto DoOutput;
else
{
2003-06-06 02:34:03 +00:00
m_outputBlocked = true;
2002-10-04 17:31:41 +00:00
return result;
}
}
2003-06-06 02:34:03 +00:00
m_outputBlocked = false;
2002-10-04 17:31:41 +00:00
byteCount += m_putSize;
2003-06-06 02:34:03 +00:00
m_dataBegin += m_putSize;
if (checkDelimiter && m_dataBegin < m_dataEnd && m_buf[m_dataBegin] == delimiter)
break;
if (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)
2002-10-04 17:31:41 +00:00
break;
}
}
return 0;
}
// *************************************************************
2003-06-19 17:09:07 +00:00
NetworkSink::NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound)
: m_maxBufferSize(maxBufferSize), m_autoFlushBound(autoFlushBound)
, m_needSendResult(false), m_wasBlocked(false)
, m_buffer(STDMIN(16U*1024U+256, maxBufferSize)), m_skipBytes(0)
, m_speedTimer(Timer::MILLISECONDS), m_byteCountSinceLastTimerReset(0)
, m_currentSpeed(0), m_maxObservedSpeed(0)
2003-06-06 02:34:03 +00:00
{
}
2003-06-19 17:09:07 +00:00
float NetworkSink::ComputeCurrentSpeed()
{
if (m_speedTimer.ElapsedTime() > 1000)
{
m_currentSpeed = m_byteCountSinceLastTimerReset * 1000 / m_speedTimer.ElapsedTime();
m_maxObservedSpeed = STDMAX(m_currentSpeed, m_maxObservedSpeed * 0.98f);
m_byteCountSinceLastTimerReset = 0;
m_speedTimer.StartTimer();
// OutputDebugString(("max speed: " + IntToString((int)m_maxObservedSpeed) + " current speed: " + IntToString((int)m_currentSpeed) + "\n").c_str());
}
return m_currentSpeed;
}
2002-10-04 17:31:41 +00:00
unsigned int NetworkSink::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking)
{
2003-06-19 17:09:07 +00:00
if (m_skipBytes)
2002-10-04 17:31:41 +00:00
{
2003-06-19 17:09:07 +00:00
assert(length >= m_skipBytes);
inString += m_skipBytes;
length -= m_skipBytes;
2002-10-04 17:31:41 +00:00
}
m_buffer.LazyPut(inString, length);
2002-10-04 17:31:41 +00:00
2003-06-19 17:09:07 +00:00
if (!blocking || m_buffer.CurrentSize() > m_autoFlushBound)
TimedFlush(0, 0);
2002-10-04 17:31:41 +00:00
unsigned int targetSize = messageEnd ? 0 : m_maxBufferSize;
2003-06-19 17:09:07 +00:00
if (blocking)
TimedFlush(INFINITE_TIME, targetSize);
2002-10-04 17:31:41 +00:00
if (m_buffer.CurrentSize() > targetSize)
{
assert(!blocking);
2003-06-19 17:09:07 +00:00
unsigned int blockedBytes = STDMIN(m_buffer.CurrentSize() - targetSize, (unsigned long)length);
m_buffer.UndoLazyPut(blockedBytes);
m_buffer.FinalizeLazyPut();
2003-06-19 17:09:07 +00:00
m_wasBlocked = true;
m_skipBytes += length - blockedBytes;
return STDMAX(blockedBytes, 1U);
2002-10-04 17:31:41 +00:00
}
m_buffer.FinalizeLazyPut();
2003-06-19 17:09:07 +00:00
m_wasBlocked = false;
m_skipBytes = 0;
2002-10-04 17:31:41 +00:00
if (messageEnd)
AccessSender().SendEof();
return 0;
}
unsigned int NetworkSink::TimedFlush(unsigned long maxTime, unsigned int targetSize)
{
NetworkSender &sender = AccessSender();
bool forever = maxTime == INFINITE_TIME;
Timer timer(Timer::MILLISECONDS, forever);
unsigned int totalFlushSize = 0;
while (true)
{
2003-06-06 02:34:03 +00:00
if (m_buffer.CurrentSize() <= targetSize)
break;
2002-10-04 17:31:41 +00:00
if (m_needSendResult)
{
2003-06-06 02:34:03 +00:00
if (sender.MustWaitForResult() && !sender.Wait(SaturatingSubtract(maxTime, timer.ElapsedTime())))
break;
2002-10-04 17:31:41 +00:00
unsigned int sendResult = sender.GetSendResult();
2003-06-19 17:09:07 +00:00
#if CRYPTOPP_TRACE_NETWORK
OutputDebugString((IntToString((unsigned int)this) + ": Sent " + IntToString(sendResult) + " bytes\n").c_str());
#endif
2002-10-04 17:31:41 +00:00
m_buffer.Skip(sendResult);
totalFlushSize += sendResult;
m_needSendResult = false;
2003-06-06 02:34:03 +00:00
if (!m_buffer.AnyRetrievable())
2002-10-04 17:31:41 +00:00
break;
}
2003-06-06 02:34:03 +00:00
unsigned long timeOut = maxTime ? SaturatingSubtract(maxTime, timer.ElapsedTime()) : 0;
if (sender.MustWaitToSend() && !sender.Wait(timeOut))
break;
2002-10-04 17:31:41 +00:00
unsigned int contiguousSize = 0;
const byte *block = m_buffer.Spy(contiguousSize);
2003-06-19 17:09:07 +00:00
#if CRYPTOPP_TRACE_NETWORK
OutputDebugString((IntToString((unsigned int)this) + ": Sending " + IntToString(contiguousSize) + " bytes\n").c_str());
#endif
2002-10-04 17:31:41 +00:00
sender.Send(block, contiguousSize);
m_needSendResult = true;
2003-06-06 02:34:03 +00:00
if (maxTime > 0 && timeOut == 0)
break; // once time limit is reached, return even if there is more data waiting
2002-10-04 17:31:41 +00:00
}
2003-06-19 17:09:07 +00:00
m_byteCountSinceLastTimerReset += totalFlushSize;
ComputeCurrentSpeed();
2002-10-04 17:31:41 +00:00
return totalFlushSize;
}
#endif // #ifdef HIGHRES_TIMER_AVAILABLE
NAMESPACE_END