- Main Page
- Namespaces
- Classes
- Files

# winpipes.cpp

    00001 // winpipes.cpp - written and placed in the public domain by Wei Dai
    00002
    00003 #include "pch.h"
    00004 #include "winpipes.h"
    00005
    00006 #ifdef WINDOWS_PIPES_AVAILABLE
    00007
    00008 #include "wait.h"
    00009
    00010 NAMESPACE_BEGIN(CryptoPP)
    00011
    00012 WindowsHandle::WindowsHandle(HANDLE h, bool own)
    00013         : m_h(h), m_own(own)
    00014 {
    00015 }
    00016
    00017 WindowsHandle::~WindowsHandle()
    00018 {
    00019         if (m_own)
    00020         {
    00021                 try
    00022                 {
    00023                         CloseHandle();
    00024                 }
    00025                 catch (...)
    00026                 {
    00027                 }
    00028         }
    00029 }
    00030
    00031 bool WindowsHandle::HandleValid() const
    00032 {
    00033         return m_h && m_h != INVALID_HANDLE_VALUE;
    00034 }
    00035
    00036 void WindowsHandle::AttachHandle(HANDLE h, bool own)
    00037 {
    00038         if (m_own)
    00039                 CloseHandle();
    00040
    00041         m_h = h;
    00042         m_own = own;
    00043         HandleChanged();
    00044 }
    00045
    00046 HANDLE WindowsHandle::DetachHandle()
    00047 {
    00048         HANDLE h = m_h;
    00049         m_h = INVALID_HANDLE_VALUE;
    00050         HandleChanged();
    00051         return h;
    00052 }
    00053
    00054 void WindowsHandle::CloseHandle()
    00055 {
    00056         if (m_h != INVALID_HANDLE_VALUE)
    00057         {
    00058                 ::CloseHandle(m_h);
    00059                 m_h = INVALID_HANDLE_VALUE;
    00060                 HandleChanged();
    00061         }
    00062 }
    00063
    00064 // ********************************************************
    00065
    00066 void WindowsPipe::HandleError(const char *operation) const
    00067 {
    00068         DWORD err = GetLastError();
    00069         throw Err(GetHandle(), operation, err);
    00070 }
    00071
    00072 WindowsPipe::Err::Err(HANDLE s, const std::string& operation, int error)
    00073         : OS_Error(IO_ERROR, "WindowsPipe: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error)
    00074         , m_h(s)
    00075 {
    00076 }
    00077
    00078 // *************************************************************
    00079
    00080 WindowsPipeReceiver::WindowsPipeReceiver()
    00081         : m_resultPending(false), m_eofReceived(false)
    00082 {
    00083         m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
    00084         CheckAndHandleError("CreateEvent", m_event.HandleValid());
    00085         memset(&m_overlapped, 0, sizeof(m_overlapped));
    00086         m_overlapped.hEvent = m_event;
    00087 }
    00088
    00089 bool WindowsPipeReceiver::Receive(byte* buf, size_t bufLen)
    00090 {
    00091         assert(!m_resultPending && !m_eofReceived);
    00092
    00093         HANDLE h = GetHandle();
    00094         // don't queue too much at once, or we might use up non-paged memory
    00095         if (ReadFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &m_lastResult, &m_overlapped))
    00096         {
    00097                 if (m_lastResult == 0)
    00098                         m_eofReceived = true;
    00099         }
    00100         else
    00101         {
    00102                 switch (GetLastError())
    00103                 {
    00104                 default:
    00105                         CheckAndHandleError("ReadFile", false);
    00106                 case ERROR_BROKEN_PIPE:
    00107                 case ERROR_HANDLE_EOF:
    00108                         m_lastResult = 0;
    00109                         m_eofReceived = true;
    00110                         break;
    00111                 case ERROR_IO_PENDING:
    00112                         m_resultPending = true;
    00113                 }
    00114         }
    00115         return !m_resultPending;
    00116 }
    00117
    00118 void WindowsPipeReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
    00119 {
    00120         if (m_resultPending)
    00121                 container.AddHandle(m_event, CallStack("WindowsPipeReceiver::GetWaitObjects() - result pending", &callStack));
    00122         else if (!m_eofReceived)
    00123                 container.SetNoWait(CallStack("WindowsPipeReceiver::GetWaitObjects() - result ready", &callStack));
    00124 }
    00125
    00126 unsigned int WindowsPipeReceiver::GetReceiveResult()
    00127 {
    00128         if (m_resultPending)
    00129         {
    00130                 HANDLE h = GetHandle();
    00131                 if (GetOverlappedResult(h, &m_overlapped, &m_lastResult, false))
    00132                 {
    00133                         if (m_lastResult == 0)
    00134                                 m_eofReceived = true;
    00135                 }
    00136                 else
    00137                 {
    00138                         switch (GetLastError())
    00139                         {
    00140                         default:
    00141                                 CheckAndHandleError("GetOverlappedResult", false);
    00142                         case ERROR_BROKEN_PIPE:
    00143                         case ERROR_HANDLE_EOF:
    00144                                 m_lastResult = 0;
    00145                                 m_eofReceived = true;
    00146                         }
    00147                 }
    00148                 m_resultPending = false;
    00149         }
    00150         return m_lastResult;
    00151 }
    00152
    00153 // *************************************************************
    00154
    00155 WindowsPipeSender::WindowsPipeSender()
    00156         : m_resultPending(false), m_lastResult(0)
    00157 {
    00158         m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
    00159         CheckAndHandleError("CreateEvent", m_event.HandleValid());
    00160         memset(&m_overlapped, 0, sizeof(m_overlapped));
    00161         m_overlapped.hEvent = m_event;
    00162 }
    00163
    00164 void WindowsPipeSender::Send(const byte* buf, size_t bufLen)
    00165 {
    00166         DWORD written = 0;
    00167         HANDLE h = GetHandle();
    00168         // don't queue too much at once, or we might use up non-paged memory
    00169         if (WriteFile(h, buf, UnsignedMin((DWORD)128*1024, bufLen), &written, &m_overlapped))
    00170         {
    00171                 m_resultPending = false;
    00172                 m_lastResult = written;
    00173         }
    00174         else
    00175         {
    00176                 if (GetLastError() != ERROR_IO_PENDING)
    00177                         CheckAndHandleError("WriteFile", false);
    00178
    00179                 m_resultPending = true;
    00180         }
    00181 }
    00182
    00183 void WindowsPipeSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
    00184 {
    00185         if (m_resultPending)
    00186                 container.AddHandle(m_event, CallStack("WindowsPipeSender::GetWaitObjects() - result pending", &callStack));
    00187         else
    00188                 container.SetNoWait(CallStack("WindowsPipeSender::GetWaitObjects() - result ready", &callStack));
    00189 }
    00190
    00191 unsigned int WindowsPipeSender::GetSendResult()
    00192 {
    00193         if (m_resultPending)
    00194         {
    00195                 HANDLE h = GetHandle();
    00196                 BOOL result = GetOverlappedResult(h, &m_overlapped, &m_lastResult, false);
    00197                 CheckAndHandleError("GetOverlappedResult", result);
    00198                 m_resultPending = false;
    00199         }
    00200         return m_lastResult;
    00201 }
    00202
    00203 NAMESPACE_END
    00204
    00205 #endif