SocketClientImpl.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #ifndef SOCKETCLIENTIMPL_H
  2. #define SOCKETCLIENTIMPL_H
  3. #pragma once
  4. #pragma warning(push)
  5. #pragma warning(disable:4995)
  6. #include <vector>
  7. #pragma warning(pop)
  8. #include "SocketHandle.h"
  9. /**
  10. * ISocketClientHandler
  11. * Event handler that SocketClientImpl<T> must implement
  12. * This class is not required, you can do the same thing as long your class exposes these functions.
  13. * (These are not pure to save you some typing)
  14. */
  15. class ISocketClientHandler
  16. {
  17. public:
  18. virtual void OnThreadBegin(CSocketHandle* ) {}
  19. virtual void OnThreadExit(CSocketHandle* ) {}
  20. virtual void OnDataReceived(CSocketHandle* , const BYTE* , DWORD , const SockAddrIn& ) {}
  21. virtual void OnConnectionDropped(CSocketHandle* ) {}
  22. virtual void OnConnectionError(CSocketHandle* , DWORD ) {}
  23. };
  24. /**
  25. * SocketClientImpl<T, tBufferSize>
  26. * Because <typename T> may refer to any class of your choosing,
  27. * Client Communication wrapper
  28. */
  29. template <typename T, size_t tBufferSize = 2048>
  30. class SocketClientImpl
  31. {
  32. typedef SocketClientImpl<T, tBufferSize> thisClass;
  33. public:
  34. SocketClientImpl()
  35. : _pInterface(0)
  36. , _thread(0)
  37. , _threadExit(0)
  38. {
  39. }
  40. void SetInterface(T* pInterface)
  41. {
  42. ::InterlockedExchangePointer(reinterpret_cast<void**>(&_pInterface), pInterface);
  43. }
  44. operator CSocketHandle*() throw()
  45. {
  46. return( &_socket );
  47. }
  48. CSocketHandle* operator->() throw()
  49. {
  50. return( &_socket );
  51. }
  52. bool IsOpen() const
  53. {
  54. return _socket.IsOpen();
  55. }
  56. bool CreateSocket(LPCTSTR pszHost, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
  57. {
  58. return _socket.CreateSocket(pszHost, pszServiceName, nFamily, nType, uOptions);
  59. }
  60. bool ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType)
  61. {
  62. return _socket.ConnectTo(pszHostName, pszRemote, pszServiceName, nFamily, nType);
  63. }
  64. void Close()
  65. {
  66. _socket.Close();
  67. }
  68. DWORD Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
  69. {
  70. return _socket.Read(lpBuffer, dwSize, lpAddrIn, dwTimeout);
  71. }
  72. DWORD Write(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
  73. {
  74. return _socket.Write(lpBuffer, dwCount, lpAddrIn, dwTimeout);
  75. }
  76. bool StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0);
  77. void Terminate(DWORD dwTimeout = INFINITE);
  78. static bool IsConnectionDropped(DWORD dwError);
  79. protected:
  80. void Run();
  81. static DWORD WINAPI SocketClientProc(thisClass* _this);
  82. T* _pInterface;
  83. HANDLE _thread;
  84. CSocketHandle _socket;
  85. HANDLE _threadExit;
  86. };
  87. template <typename T, size_t tBufferSize>
  88. bool SocketClientImpl<T, tBufferSize>::StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
  89. {
  90. // must be closed first...
  91. if ( IsOpen() ) return false;
  92. bool result = false;
  93. if ( nType == SOCK_STREAM )
  94. {
  95. result = _socket.ConnectTo(pszHost, pszRemote, pszServiceName, nFamily, nType); // TCP
  96. }
  97. else
  98. {
  99. // let provider select a port for us
  100. result = _socket.CreateSocket(pszHost, TEXT("0"), nFamily, nType, uOptions); // UDP
  101. }
  102. if ( result )
  103. {
  104. _threadExit = ::CreateEvent(
  105. NULL, /* Security */
  106. TRUE, /* Manual event */
  107. 0, /* Clear on creation */
  108. 0 );//"Kernel::_threadExit");
  109. _thread = AtlCreateThread(SocketClientProc, this);
  110. if ( _thread == NULL )
  111. {
  112. DWORD dwError = GetLastError();
  113. _socket.Close();
  114. SetLastError(dwError);
  115. result = false;
  116. }
  117. }
  118. return result;
  119. }
  120. template <typename T, size_t tBufferSize>
  121. void SocketClientImpl<T, tBufferSize>::Run()
  122. {
  123. SockAddrIn addrIn;
  124. std::vector<unsigned char> data;
  125. data.resize( tBufferSize );
  126. DWORD dwRead;
  127. DWORD dwError;
  128. _ASSERTE( _pInterface != NULL && "Need an interface to pass events");
  129. // Notification: OnThreadBegin
  130. if ( _pInterface != NULL ) {
  131. _pInterface->OnThreadBegin(*this);
  132. }
  133. int type = _socket.GetSocketType();
  134. if (type == SOCK_STREAM) {
  135. _socket.GetPeerName( addrIn );
  136. }
  137. //while ( _socket.IsOpen() )
  138. do
  139. {
  140. if( _socket.IsOpen() )
  141. {
  142. if (type == SOCK_STREAM)
  143. {
  144. dwRead = _socket.Read(&data[0], tBufferSize, NULL, INFINITE);
  145. }
  146. else
  147. {
  148. dwRead = _socket.Read(&data[0], tBufferSize, addrIn, INFINITE);
  149. }
  150. if ( (dwRead != -1L) && (dwRead > 0))
  151. {
  152. // Notification: OnDataReceived
  153. if ( _pInterface != NULL ) {
  154. _pInterface->OnDataReceived(*this, &data[0], dwRead, addrIn);
  155. }
  156. }
  157. else if (type == SOCK_STREAM && dwRead == 0L )
  158. {
  159. // connection broken
  160. if ( _pInterface != NULL )
  161. {
  162. _pInterface->OnConnectionDropped(*this);
  163. }
  164. break;
  165. }
  166. else if ( dwRead == -1L )
  167. {
  168. dwError = GetLastError();
  169. if ( _pInterface != NULL )
  170. {
  171. if (IsConnectionDropped( dwError) ) {
  172. // Notification: OnConnectionDropped
  173. if (type == SOCK_STREAM || (dwError == WSAENOTSOCK || dwError == WSAENETDOWN))
  174. {
  175. _pInterface->OnConnectionDropped(*this);
  176. break;
  177. }
  178. }
  179. // Notification: OnConnectionError
  180. _pInterface->OnConnectionError(*this, dwError);
  181. }
  182. else {
  183. break;
  184. }
  185. }
  186. }
  187. }while( WaitForSingleObject(_threadExit, 125L) == WAIT_TIMEOUT );
  188. data.clear();
  189. // Notification: OnThreadExit
  190. if ( _pInterface != NULL ) {
  191. _pInterface->OnThreadExit(*this);
  192. }
  193. }
  194. template <typename T, size_t tBufferSize>
  195. void SocketClientImpl<T, tBufferSize>::Terminate(DWORD dwTimeout /*= INFINITE*/)
  196. {
  197. if (_threadExit != NULL)
  198. {
  199. SetEvent( _threadExit );
  200. }
  201. _socket.Close();
  202. if ( _thread != NULL )
  203. {
  204. WaitForSingleObject( _thread, INFINITE );
  205. CloseHandle( _thread );
  206. _thread = NULL;
  207. #if 0
  208. if ( WaitForSingleObject(_thread, dwTimeout) == WAIT_TIMEOUT ) {
  209. TerminateThread(_thread, 1);
  210. }
  211. CloseHandle(_thread);
  212. _thread = NULL;
  213. #endif
  214. }
  215. }
  216. template <typename T, size_t tBufferSize>
  217. DWORD WINAPI SocketClientImpl<T, tBufferSize>::SocketClientProc(thisClass* _this)
  218. {
  219. if ( _this != NULL )
  220. {
  221. _this->Run();
  222. }
  223. return 0;
  224. }
  225. template <typename T, size_t tBufferSize>
  226. bool SocketClientImpl<T, tBufferSize>::IsConnectionDropped(DWORD dwError)
  227. {
  228. // see: winerror.h for definition
  229. switch( dwError )
  230. {
  231. case WSAENOTSOCK:
  232. case WSAENETDOWN:
  233. case WSAENETUNREACH:
  234. case WSAENETRESET:
  235. case WSAECONNABORTED:
  236. case WSAECONNRESET:
  237. case WSAESHUTDOWN:
  238. case WSAEHOSTDOWN:
  239. case WSAEHOSTUNREACH:
  240. return true;
  241. default:
  242. break;
  243. }
  244. return false;
  245. }
  246. #endif //SOCKETCLIENTIMPL_H