From 539364846a89987ac2679988653f50332cb91d26 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Thu, 30 Aug 2012 21:06:13 +0000 Subject: Implemented 1.3.2 protocol encryption using CryptoPP, up to Client Status packet (http://wiki.vg/Protocol_FAQ step 14) git-svn-id: http://mc-server.googlecode.com/svn/trunk@808 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- CryptoPP/wait.cpp | 397 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 397 insertions(+) create mode 100644 CryptoPP/wait.cpp (limited to 'CryptoPP/wait.cpp') diff --git a/CryptoPP/wait.cpp b/CryptoPP/wait.cpp new file mode 100644 index 000000000..198785838 --- /dev/null +++ b/CryptoPP/wait.cpp @@ -0,0 +1,397 @@ +// wait.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "wait.h" +#include "misc.h" + +#ifdef SOCKETS_AVAILABLE + +#ifdef USE_BERKELEY_STYLE_SOCKETS +#include +#include +#include +#include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +unsigned int WaitObjectContainer::MaxWaitObjects() +{ +#ifdef USE_WINDOWS_STYLE_SOCKETS + return MAXIMUM_WAIT_OBJECTS * (MAXIMUM_WAIT_OBJECTS-1); +#else + return FD_SETSIZE; +#endif +} + +WaitObjectContainer::WaitObjectContainer(WaitObjectsTracer* tracer) + : m_tracer(tracer), m_eventTimer(Timer::MILLISECONDS) + , m_sameResultCount(0), m_noWaitTimer(Timer::MILLISECONDS) +{ + Clear(); + m_eventTimer.StartTimer(); +} + +void WaitObjectContainer::Clear() +{ +#ifdef USE_WINDOWS_STYLE_SOCKETS + m_handles.clear(); +#else + m_maxFd = 0; + FD_ZERO(&m_readfds); + FD_ZERO(&m_writefds); +#endif + m_noWait = false; + m_firstEventTime = 0; +} + +inline void WaitObjectContainer::SetLastResult(LastResultType result) +{ + if (result == m_lastResult) + m_sameResultCount++; + else + { + m_lastResult = result; + m_sameResultCount = 0; + } +} + +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; +} + +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 + +struct WaitingThreadData +{ + bool waitingToWait, terminate; + HANDLE startWaiting, stopWaiting; + const HANDLE *waitHandles; + unsigned int count; + HANDLE threadHandle; + DWORD threadId; + DWORD* error; +}; + +WaitObjectContainer::~WaitObjectContainer() +{ + try // don't let exceptions escape destructor + { + if (!m_threads.empty()) + { + HANDLE threadHandles[MAXIMUM_WAIT_OBJECTS]; + unsigned int i; + for (i=0; i pThread((WaitingThreadData *)lParam); + WaitingThreadData &thread = *pThread; + std::vector handles; + + while (true) + { + thread.waitingToWait = true; + ::WaitForSingleObject(thread.startWaiting, INFINITE); + thread.waitingToWait = false; + + if (thread.terminate) + break; + if (!thread.count) + continue; + + handles.resize(thread.count + 1); + handles[0] = thread.stopWaiting; + std::copy(thread.waitHandles, thread.waitHandles+thread.count, handles.begin()+1); + + DWORD result = ::WaitForMultipleObjects((DWORD)handles.size(), &handles[0], FALSE, INFINITE); + + if (result == WAIT_OBJECT_0) + continue; // another thread finished waiting first, so do nothing + SetEvent(thread.stopWaiting); + if (!(result > WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + handles.size())) + { + assert(!"error in WaitingThread"); // break here so we can see which thread has an error + *thread.error = ::GetLastError(); + } + } + + return S_OK; // return a value here to avoid compiler warning +} + +void WaitObjectContainer::CreateThreads(unsigned int count) +{ + size_t currentCount = m_threads.size(); + if (currentCount == 0) + { + m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL); + m_stopWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL); + } + + if (currentCount < count) + { + m_threads.resize(count); + for (size_t i=currentCount; i 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 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())); + } +} + +#else // #ifdef USE_WINDOWS_STYLE_SOCKETS + +void WaitObjectContainer::AddReadFd(int fd, CallStack const& callStack) // TODO: do something with callStack +{ + FD_SET(fd, &m_readfds); + m_maxFd = STDMAX(m_maxFd, fd); +} + +void WaitObjectContainer::AddWriteFd(int fd, CallStack const& callStack) // TODO: do something with callStack +{ + FD_SET(fd, &m_writefds); + m_maxFd = STDMAX(m_maxFd, fd); +} + +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); +} + +#endif + +// ******************************************************** + +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; + GetWaitObjects(container, callStack); // reduce clutter by not adding this func to stack + return container.Wait(milliseconds); +} + +NAMESPACE_END + +#endif -- cgit v1.2.3