Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

IoCompletionListener.h

Go to the documentation of this file.
00001 /*  IoCompletionListener.h - IOCP socket listener
00002     Copyright (C) 2001-2004 Mark Weaver
00003     Written by Mark Weaver <mark@npsl.co.uk>
00004 
00005     Part of the Open-Win32 library.
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public
00017     License along with this library; if not, write to the
00018     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019     Boston, MA  02111-1307, USA.
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 /*cbTransferred*/) = 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         // Create an explicitly non-blocking socket: for apps that are naughty (like
00132         // perl) and turn off the overlapped flag by default
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     /* The overlapped structure in use */
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         // Create an explicitly non-blocking socket: for apps that are naughty (like
00216         // perl) and turn off the overlapped flag by default
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         // Fill out the local socket's address information.
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         // Bind the socket
00228         if (::bind(m_listen, reinterpret_cast<const sockaddr *>(&local_sin), sizeof(local_sin)) == SOCKET_ERROR)
00229             return SOCKET_ERROR;
00230 
00231         // Establish a socket to listen for incoming connections.
00232         if (::listen(m_listen, SOMAXCONN) == SOCKET_ERROR)
00233             return SOCKET_ERROR;
00234 
00235         // Associated with the IOCP
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         // Store the port
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     // No copy or assignment
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 } // namespace OW32
00280 
00281 #endif // OW32_IoCompletionListener_h

Generated on Sun Jun 5 01:29:17 2005 for OW32 by  doxygen 1.3.9.1