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

Listener.h

Go to the documentation of this file.
00001 /*  Listener.h - IOCP socket listener helper functions
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_Listener_h
00027 #define OW32_Listener_h
00028 
00029 #include <OW32/Socket.h>
00030 #include <OW32/AsyncSocket.h>
00031 #include <OW32/XSOCKET.h>
00032 #include <OW32/IoCompletion.h>
00033 #include <OW32/SyncObjects.h>
00034 
00035 namespace OW32 
00036 {
00037 
00038 class OW32_LIB_EXPORT CListener;
00039 
00041 class OW32_LIB_EXPORT CListenerCallback
00042 {
00043 public:
00050     virtual BOOL onAcceptCompletion(CListener* /*listener*/, BOOL bRet, DWORD /*cbTransferred*/) { return bRet; }
00051 };
00052 
00054 class OW32_LIB_EXPORT CListener
00055 {
00056 public:
00060     CListener(CListenerCallback* pCallback) :
00061         m_pCallback(pCallback),
00062         m_port(0)
00063     {
00064     }
00065 
00067     virtual ~CListener() = 0 {}
00068     
00072     virtual void Cancel()
00073     {
00074         m_sListen.close();
00075     }
00076 
00080     virtual bool Cancelled()
00081     {
00082         return m_sListen == INVALID_SOCKET;
00083     }
00084 
00086     CListenerCallback *GetCallback() const
00087     {
00088         return m_pCallback;
00089     }
00090 
00092     int GetPort() const { return m_port; }
00093 
00097     virtual BOOL Listen(int port)
00098     {
00099         // Create an explicitly non-blocking socket: for apps that are naughty (like
00100         // perl) and turn off the overlapped flag by default
00101         m_sListen.Attach(WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED));
00102         if (m_sListen == INVALID_SOCKET)
00103             return FALSE;
00104 
00105         // Fill out the local socket's address information.
00106         CSockAddrIn local_sin(htons (static_cast<u_short>(port)));
00107         if (m_sListen.bind(local_sin)==SOCKET_ERROR)
00108             return FALSE;
00109 
00110         // Establish a socket to listen for incoming connections.
00111         if (m_sListen.listen (SOMAXCONN) == SOCKET_ERROR)
00112             return FALSE;
00113 
00114         m_port = port;
00115         return TRUE;
00116     }
00117 
00119     virtual int Accept()=0;
00120 
00124     virtual int ListenAndAccept(int port)
00125     {
00126         return (Listen(port) != SOCKET_ERROR && Accept() != SOCKET_ERROR) ? 0 : SOCKET_ERROR;
00127     }
00128 
00133     virtual int GetAddresses(sockaddr_in** local_address, sockaddr_in** remote_address)=0;
00134 
00138     virtual int GetRemoteAddress(sockaddr_in** remote_address)
00139     {
00140         return GetAddresses(NULL,remote_address);
00141     }
00142 
00146     virtual int GetLocalAddress(sockaddr_in** local_address)
00147     {
00148         GetAddresses(local_address,NULL);
00149         return 0;
00150     }
00151 
00153     virtual SOCKET DetachAcceptedSocket() {
00154         return m_sAccepted.Detach();
00155     }
00156 
00157 protected:
00159     int m_port;
00161     CSocket m_sListen;
00163     XSOCKET m_sAccepted;
00165     CListenerCallback* m_pCallback;
00166 };
00167 
00169 class OW32_LIB_EXPORT CIoCompletionListener : 
00170     public CListener, 
00171     public CIoCompletion
00172 {
00173 public:
00175     DLL_IMPLEMENT_IO_COMPLETION(CIoCompletionListener, OW32_LIB_EXPORT)
00176 
00177     
00180     CIoCompletionListener(CListenerCallback* pCallback) :
00181         CListener(pCallback)
00182     {
00183         ZeroMemory(&m_os, sizeof(m_os));
00184         m_os.lpCompletion = onAcceptCompletion;
00185     }
00186 
00190     virtual void Cancel()
00191     {
00192         CSingleLock lock(m_socketLock);
00193         m_sListen.close();
00194     }
00195 
00199     virtual bool Cancelled()
00200     {
00201         CSingleLock lock(m_socketLock);
00202         return m_sListen == INVALID_SOCKET;
00203     }
00204 
00206     void onAcceptCompletion(BOOL bRet, DWORD cbTransferred, LPOVERLAPPED /*lpOS*/)
00207     {
00208         if (m_pCallback->onAcceptCompletion(this, bRet, cbTransferred))
00209         {
00210             while (Accept() == SOCKET_ERROR && m_pCallback->onAcceptCompletion(this, FALSE, 0))
00211                 ;
00212         }
00213     }
00214 
00218     virtual int Listen(int port)
00219     {
00220         // Create an explicitly non-blocking socket: for apps that are naughty (like
00221         // perl) and turn off the overlapped flag by default
00222         m_sListen.Attach(WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED));
00223         if (m_sListen == INVALID_SOCKET)
00224             return FALSE;
00225 
00226         // Fill out the local socket's address information.
00227         CSockAddrIn local_sin(htons (static_cast<u_short>(port)));
00228         if (m_sListen.bind(local_sin)==SOCKET_ERROR)
00229             return SOCKET_ERROR;
00230 
00231         // Establish a socket to listen for incoming connections.
00232         if (m_sListen.listen (SOMAXCONN) == SOCKET_ERROR)
00233             return SOCKET_ERROR;
00234 
00235         m_port = port;
00236         return 0;
00237     }
00238 
00240     virtual int Accept()
00241     {
00242         // Create an explicitly non-blocking socket: for apps that are naughty (like
00243         // perl) and turn off the overlapped flag by default
00244         m_sAccepted = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED);
00245         if (m_sAccepted == SOCKET_ERROR)
00246             return SOCKET_ERROR;
00247 
00248         DWORD dwDummy=0;
00249         CSingleLock lock(m_socketLock);
00250         if (!AcceptEx(m_sListen, m_sAccepted, m_buffer, 0, 
00251              sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16,
00252              &dwDummy, &m_os)) 
00253         {
00254             DWORD error = ::GetLastError();
00255             lock.Unlock();
00256             if (error != ERROR_IO_PENDING)
00257                 return SOCKET_ERROR;
00258         }
00259         return 0;
00260     }
00261 
00263     int ListenAndAcceptWithPort(int Port, HANDLE hCompletionPort)
00264     {
00265         return (Listen(Port) != SOCKET_ERROR && 
00266                associateWithIoCompletionPort(hCompletionPort) && 
00267                Accept() != SOCKET_ERROR) ? 0 : SOCKET_ERROR;
00268     }
00269 
00274     virtual int GetAddresses(sockaddr_in** local_address, sockaddr_in** remote_address)
00275     {
00276         INT local_address_len = sizeof(sockaddr_in);
00277         INT remote_address_len = sizeof(sockaddr_in);
00278         sockaddr *temp_local, *temp_remote;
00279         GetAcceptExSockaddrs(m_buffer, 0, sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, 
00280             local_address ? (sockaddr**)local_address : &temp_local, &local_address_len,
00281             remote_address ? (sockaddr**)remote_address : &temp_remote, &remote_address_len);
00282         return 0;
00283     }
00284 
00289     BOOL associateWithIoCompletionPort(HANDLE hCompletionPort)
00290     {
00291         return CreateIoCompletionPort(
00292             (HANDLE)(SOCKET)m_sListen, hCompletionPort, 
00293             reinterpret_cast<ULONG_PTR>(static_cast<CIoCompletion*>(this)), 0) != NULL;
00294     }
00295 
00297     operator SOCKET() { return m_sListen; }
00298 
00299 private:
00300     // No copy or assignment
00301     CIoCompletionListener(const CIoCompletionListener& other);
00302     CIoCompletionListener& operator=(const CIoCompletionListener& other);
00303 
00304     char m_buffer[(sizeof(sockaddr_in)+16)*2];
00305     OVERLAPPEDPLUS m_os;
00306     CCriticalSection m_socketLock;
00307 };
00308 
00310 class OW32_LIB_EXPORT CMessageListener : 
00311     public CListener, 
00312     public CAsyncSocketCallback
00313 {
00314 public:
00318     CMessageListener(CListenerCallback* pCallback) :
00319         CListener(pCallback)
00320     {
00321     }
00322 
00324     void onAcceptCompletion(BOOL bRet)
00325     {
00326         bRet;
00327         int sock_addr_len = sizeof(m_remote_addr);
00328         m_sAccepted = m_sListen.accept(&m_remote_addr, &sock_addr_len);
00329         if (m_pCallback->onAcceptCompletion(this, m_sAccepted!=SOCKET_ERROR, 0))
00330         {
00331             while (!Accept() && m_pCallback->onAcceptCompletion(this, FALSE, 0))
00332                 ;
00333         }
00334     }
00335 
00337     int Accept();
00338 
00343     virtual int GetAddresses(sockaddr_in** local_addr, sockaddr_in** remote_addr)
00344     {
00345         if (remote_addr)
00346             *remote_addr = (sockaddr_in*)&m_remote_addr;
00347         if (local_addr)
00348         {
00349             *local_addr = 0; // just in case
00350             int local_addr_len = sizeof(m_local_addr);
00351             if (getsockname(m_sAccepted, &m_local_addr, &local_addr_len)==SOCKET_ERROR)
00352                 return SOCKET_ERROR;
00353             *local_addr = (sockaddr_in*)&m_local_addr;
00354         }
00355         return 0;
00356     }
00357 
00359     operator SOCKET() { return m_sListen; }
00360 
00361 private:
00362     // No copy or assignment
00363     CMessageListener(const CMessageListener& other);
00364     CMessageListener& operator=(const CMessageListener& other);
00365 
00366     sockaddr m_remote_addr,m_local_addr;
00367 };
00368 
00369 } // namespace OW32
00370 
00371 #endif // OW32_Listener_h

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