00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00026 #ifndef OW32_IoCompletionListener_h
00027 #define OW32_IoCompletionListener_h
00028
00029 #include <OW32/XSOCKET.h>
00030 #include <OW32/SyncObjects.h>
00031
00032 namespace OW32
00033 {
00034
00035 class CIoCompletionListenerAcceptEx;
00036 class CIoCompletionListener;
00037
00041 class OW32_LIB_EXPORT CIoCompletionListenerCallback
00042 {
00043 public:
00056 virtual void onAcceptCompletion(CIoCompletionListenerAcceptEx *accepted, bool bRet, DWORD ) = 0;
00057 };
00058
00062 class CIoCompletionListenerAcceptEx :
00063 public CIoCompletion
00064 {
00065 public:
00072 CIoCompletionListenerAcceptEx(CIoCompletionListener *listener, CIoCompletionListenerCallback *callback) :
00073 m_listener(listener),
00074 m_callback(callback)
00075 {
00076 ZeroMemory(&m_os, sizeof(OVERLAPPED));
00077 }
00078
00086 virtual void OnIoCompletion(BOOL bRet, DWORD dwBytes, LPOVERLAPPED lpOS)
00087 {
00088 lpOS;
00089 m_callback->onAcceptCompletion(this, !!bRet, dwBytes);
00090 }
00091
00098 void getAddresses(sockaddr_in **local_address, sockaddr_in **remote_address)
00099 {
00100 INT local_address_len = sizeof(sockaddr_in);
00101 INT remote_address_len = sizeof(sockaddr_in);
00102 sockaddr *temp_local, *temp_remote;
00103 GetAcceptExSockaddrs(m_buffer, 0, sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16,
00104 local_address ? (sockaddr**)local_address : &temp_local, &local_address_len,
00105 remote_address ? (sockaddr**)remote_address : &temp_remote, &remote_address_len);
00106 }
00107
00111 CIoCompletionListener *getListener() const
00112 {
00113 return m_listener;
00114 }
00115
00121 SOCKET detachAcceptedSocket()
00122 {
00123 return m_accepted.Detach();
00124 }
00125
00129 int post(SOCKET sListen)
00130 {
00131
00132
00133 m_accepted = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED);
00134 if (m_accepted == SOCKET_ERROR)
00135 {
00136 delete this;
00137 return SOCKET_ERROR;
00138 }
00139
00140 DWORD dwDummy = 0;
00141 if (!AcceptEx(sListen, m_accepted, m_buffer, 0,
00142 sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16,
00143 &dwDummy, &m_os))
00144 {
00145 DWORD error = ::GetLastError();
00146 if (error != ERROR_IO_PENDING)
00147 {
00148 delete this;
00149 ::SetLastError(error);
00150 return SOCKET_ERROR;
00151 }
00152 }
00153 return 0;
00154 }
00155
00156 private:
00158 CIoCompletionListener *m_listener;
00160 CIoCompletionListenerCallback *m_callback;
00162 XSOCKET m_accepted;
00164 char m_buffer[(sizeof(sockaddr_in)+16)*2];
00165
00166 OVERLAPPED m_os;
00167 };
00168
00172 class OW32_LIB_EXPORT CIoCompletionListener
00173 {
00174 public:
00176 DLL_IMPLEMENT_IO_COMPLETION(CIoCompletionListener, OW32_LIB_EXPORT)
00177
00178
00183 CIoCompletionListener(CIoCompletionListenerCallback* callback) :
00184 m_callback(callback)
00185 {
00186 }
00187
00191 void cancel()
00192 {
00193 CSingleLock lock(m_socketLock);
00194 m_listen.Close();
00195 }
00196
00200 bool cancelled()
00201 {
00202 CSingleLock lock(m_socketLock);
00203 return m_listen == INVALID_SOCKET;
00204 }
00205
00213 int listen(int port, HANDLE hCompletionPort)
00214 {
00215
00216
00217 m_listen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED);
00218 if (m_listen == INVALID_SOCKET)
00219 return FALSE;
00220
00221
00222 sockaddr_in local_sin;
00223 local_sin.sin_port = htons(static_cast<u_short>(port));
00224 local_sin.sin_addr.S_un.S_addr = INADDR_ANY;
00225 local_sin.sin_family = AF_INET;
00226
00227
00228 if (::bind(m_listen, reinterpret_cast<const sockaddr *>(&local_sin), sizeof(local_sin)) == SOCKET_ERROR)
00229 return SOCKET_ERROR;
00230
00231
00232 if (::listen(m_listen, SOMAXCONN) == SOCKET_ERROR)
00233 return SOCKET_ERROR;
00234
00235
00236 if (!CreateIoCompletionPort(
00237 reinterpret_cast<HANDLE>(static_cast<SOCKET>(m_listen)), hCompletionPort,
00238 reinterpret_cast<ULONG_PTR>(static_cast<CIoCompletion*>(this)), 0))
00239 return SOCKET_ERROR;
00240
00241
00242 m_port = port;
00243 return 0;
00244 }
00245
00254 int postAccept()
00255 {
00256 CIoCompletionListenerAcceptEx *acceptEx = new (std::nothrow) CIoCompletionListenerAcceptEx(this, m_callback);
00257 if (!acceptEx)
00258 {
00259 ::SetLastError(ERROR_INSUFFICIENT_MEMORY);
00260 return SOCKET_ERROR;
00261 }
00262 CSingleLock lock(m_socketLock);
00263 return acceptEx->post(m_listen);
00264 }
00265
00266 private:
00267
00268 CIoCompletionListener(const CIoCompletionListener& other);
00269 CIoCompletionListener& operator=(const CIoCompletionListener& other);
00270
00272 CIoCompletionListenerCallback *m_callback;
00274 CCriticalSection m_socketLock;
00276 XSOCKET m_listen;
00277 };
00278
00279 }
00280
00281 #endif // OW32_IoCompletionListener_h