00001 00007 #pragma once 00008 #include "../rpcdispatch/rpcdisp.h" 00009 #include <bzscmn/bzscmn.h> 00010 00012 template <bool _MessageOriented, bool _AutoReconnect, bool _FailTransferOnListening = false> class PipeServer 00013 { 00014 private: 00015 HANDLE m_hPipe; 00016 HANDLE m_hNextInstance; 00017 BazisLib::String m_PipeName; 00018 bool m_bReconnectPending; 00019 bool m_bClientConnected; 00020 unsigned m_Timeout; 00021 unsigned m_LastError; 00022 00023 OVERLAPPED m_Overlapped; 00024 HANDLE m_hEvt; 00025 00026 private: 00027 HANDLE CreatePipeInstance() 00028 { 00029 return CreateNamedPipe(m_PipeName.c_str(), 00030 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 00031 _MessageOriented ? (PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE) : (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE), 00032 2, 00033 131072, 00034 131072, 00035 m_Timeout, 00036 NULL); 00037 } 00038 00039 private: 00040 template<bool out> size_t TransferWithTimeout(void *pData, size_t size) 00041 { 00042 DWORD dwOk = 0; 00043 if (out) 00044 WriteFile(m_hPipe, pData, (DWORD)size, &dwOk, &m_Overlapped); 00045 else 00046 ReadFile(m_hPipe, pData, (DWORD)size, &dwOk, &m_Overlapped); 00047 m_LastError = GetLastError(); 00048 if (dwOk) 00049 return dwOk; 00050 switch (m_LastError) 00051 { 00052 case ERROR_PIPE_LISTENING: 00053 m_bClientConnected = false; 00054 return 0; 00055 case ERROR_IO_PENDING: 00056 m_bClientConnected = true; 00057 break; 00058 default: 00059 return 0; 00060 } 00061 if (WaitForSingleObject(m_hEvt, m_Timeout) == WAIT_OBJECT_0) 00062 { 00063 GetOverlappedResult(m_hPipe, &m_Overlapped, &dwOk, TRUE); 00064 return dwOk; 00065 } 00066 CancelIo(m_hPipe); 00067 GetOverlappedResult(m_hPipe, &m_Overlapped, &dwOk, TRUE); 00068 return dwOk; 00069 } 00070 00071 public: 00072 00073 unsigned GetLastOperationError() 00074 { 00075 return m_LastError; 00076 } 00077 00078 bool ReconnectPipe() 00079 { 00080 if (m_hPipe != INVALID_HANDLE_VALUE) 00081 CloseHandle(m_hPipe); 00082 if (m_hNextInstance == INVALID_HANDLE_VALUE) 00083 m_hNextInstance = CreatePipeInstance(); 00084 00085 m_hPipe = m_hNextInstance; 00086 m_hNextInstance = CreatePipeInstance(); 00087 m_bClientConnected = false; 00088 00089 m_bReconnectPending = false; 00090 if ((m_hPipe != INVALID_HANDLE_VALUE) && (m_hNextInstance != INVALID_HANDLE_VALUE)) 00091 return true; 00092 else 00093 return false; 00094 } 00095 00096 ~PipeServer() 00097 { 00098 if (m_hPipe != INVALID_HANDLE_VALUE) 00099 CloseHandle(m_hPipe); 00100 if (m_hNextInstance != INVALID_HANDLE_VALUE) 00101 CloseHandle(m_hNextInstance); 00102 if (m_hEvt != INVALID_HANDLE_VALUE) 00103 CloseHandle(m_hEvt); 00104 } 00105 00106 PipeServer(const TCHAR *pszPipeName, unsigned Timeout = 1000) 00107 : m_PipeName(pszPipeName) 00108 , m_hPipe(INVALID_HANDLE_VALUE) 00109 , m_hNextInstance(INVALID_HANDLE_VALUE) 00110 , m_bReconnectPending(false) 00111 , m_Timeout(Timeout) 00112 , m_bClientConnected(false) 00113 , m_LastError(0) 00114 { 00115 m_hEvt = CreateEvent(NULL, TRUE, FALSE, NULL); 00116 memset(&m_Overlapped, 0, sizeof(m_Overlapped)); 00117 m_Overlapped.hEvent = m_hEvt; 00118 ReconnectPipe(); 00119 } 00120 00121 size_t Send(const void *pData, size_t Size) 00122 { 00123 SIZE_T dwOk; 00124 while (!(dwOk = TransferWithTimeout<true>((void *)pData, Size))) 00125 { 00126 switch(m_LastError) 00127 { 00128 case ERROR_PIPE_LISTENING: 00129 if (_FailTransferOnListening) 00130 return false; 00131 if (!ConnectNamedPipe(m_hPipe, NULL)) 00132 return false; 00133 continue; 00134 break; 00135 case ERROR_BROKEN_PIPE: 00136 m_bReconnectPending = true; 00137 break; 00138 } 00139 return false; 00140 } 00141 return dwOk; 00142 } 00143 00144 size_t Receive(void *pData, size_t Size, bool PartialRecvAllowed = true) 00145 { 00146 size_t offset = 0; 00147 for (;;) 00148 { 00149 SIZE_T dwOk = 0; 00150 dwOk = TransferWithTimeout<false>(((char *)pData) + offset, Size - offset); 00151 if (dwOk) 00152 { 00153 if (PartialRecvAllowed) 00154 return dwOk; 00155 else 00156 { 00157 offset += dwOk; 00158 if (offset == Size) 00159 return Size; 00160 else 00161 continue; 00162 } 00163 } 00164 else 00165 { 00166 switch(m_LastError) 00167 { 00168 case ERROR_PIPE_LISTENING: 00169 if (_FailTransferOnListening) 00170 return 0; 00171 if (!ConnectNamedPipe(m_hPipe, NULL)) 00172 return 0; 00173 continue; 00174 break; 00175 case ERROR_BROKEN_PIPE: 00176 m_bReconnectPending = true; 00177 if (_AutoReconnect) 00178 { 00179 ReconnectPipe(); 00180 continue; 00181 } 00182 break; 00183 } 00184 return 0; 00185 } 00186 } 00187 } 00188 00189 bool HasDataInBuffer() 00190 { 00191 DWORD dataAvailable = 0; 00192 for (;;) 00193 { 00194 if (!PeekNamedPipe(m_hPipe, NULL, 0, NULL, &dataAvailable, NULL)) 00195 { 00196 m_LastError = GetLastError(); 00197 switch(m_LastError) 00198 { 00199 case ERROR_BROKEN_PIPE: 00200 m_bClientConnected = false; 00201 m_bReconnectPending = true; 00202 if (_AutoReconnect) 00203 { 00204 ReconnectPipe(); 00205 continue; 00206 } 00207 break; 00208 case ERROR_PIPE_LISTENING: 00209 m_bClientConnected = false; 00210 break; 00211 } 00212 return false; 00213 } 00214 m_bClientConnected = true; 00215 return (dataAvailable != 0); 00216 } 00217 } 00218 00219 bool IsClientConnected() 00220 { 00221 return m_bClientConnected; 00222 } 00223 00224 void DiscardBufferedData() 00225 { 00226 DWORD dataAvailable = 0; 00227 for (;;) 00228 { 00229 if (!PeekNamedPipe(m_hPipe, NULL, 0, NULL, &dataAvailable, NULL)) 00230 { 00231 m_LastError = GetLastError(); 00232 if (m_LastError == ERROR_BROKEN_PIPE) 00233 { 00234 m_bReconnectPending = true; 00235 if (_AutoReconnect) 00236 { 00237 ReconnectPipe(); 00238 continue; 00239 } 00240 } 00241 return; 00242 } 00243 char *pTemp = new char[dataAvailable]; 00244 Receive(pTemp, dataAvailable, false); 00245 delete pTemp; 00246 return; 00247 } 00248 } 00249 00250 bool ReconnectPending() 00251 { 00252 return m_bReconnectPending; 00253 } 00254 }; 00255