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

Generated on Sat Dec 23 02:07:11 2006 for Crypto++ by  doxygen 1.5.1-p1