Changeset 2313


Ignore:
Timestamp:
03/10/2008 23:39:59 (4 years ago)
Author:
chris
Message:

Utility classes to be used by new Windows named pipe framework.

Location:
box/trunk/lib/server
Files:
1 added
1 copied

Legend:

Unmodified
Added
Removed
  • box/trunk/lib/server/WinNamedPipeListener.h

    r2127 r2313  
    22// 
    33// File 
    4 //              Name:    SocketListen.h 
    5 //              Purpose: Stream based sockets for servers 
    6 //              Created: 2003/07/31 
    7 // 
    8 // -------------------------------------------------------------------------- 
    9  
    10 #ifndef SOCKETLISTEN__H 
    11 #define SOCKETLISTEN__H 
    12  
    13 #include <errno.h> 
    14  
    15 #ifdef HAVE_UNISTD_H 
    16         #include <unistd.h> 
    17 #endif 
    18  
    19 #ifdef HAVE_KQUEUE 
    20         #include <sys/event.h> 
    21         #include <sys/time.h> 
    22 #endif 
    23  
    24 #ifndef WIN32 
    25         #include <poll.h> 
    26 #endif 
    27  
    28 #include <new> 
    29 #include <memory> 
    30 #include <string> 
    31  
    32 #include "Socket.h" 
     4//              Name:    WinNamedPipeListener.h 
     5//              Purpose: Windows named pipe socket connection listener 
     6//                       for server 
     7//              Created: 2008/09/30 
     8// 
     9// -------------------------------------------------------------------------- 
     10 
     11#ifndef WINNAMEDPIPELISTENER__H 
     12#define WINNAMEDPIPELISTENER__H 
     13 
     14#include <OverlappedIO.h> 
     15#include <WinNamedPipeStream.h> 
     16 
    3317#include "ServerException.h" 
    3418 
     
    3822// 
    3923// Class 
    40 //              Name:    _NoSocketLocking 
    41 //              Purpose: Default locking class for SocketListen 
    42 //              Created: 2003/07/31 
    43 // 
    44 // -------------------------------------------------------------------------- 
    45 class _NoSocketLocking 
     24//              Name:    WinNamedPipeListener 
     25//              Purpose:  
     26//              Created: 2008/09/30 
     27// 
     28// -------------------------------------------------------------------------- 
     29template<int ListenBacklog = 128> 
     30class WinNamedPipeListener 
    4631{ 
    47 public: 
    48         _NoSocketLocking(int sock) 
    49         { 
    50         } 
    51          
    52         ~_NoSocketLocking() 
    53         { 
    54         } 
    55          
    56         bool HaveLock() 
    57         { 
    58                 return true; 
    59         } 
    60          
    6132private: 
    62         _NoSocketLocking(const _NoSocketLocking &rToCopy) 
    63         { 
    64         } 
    65 }; 
    66  
    67  
    68 // -------------------------------------------------------------------------- 
    69 // 
    70 // Class 
    71 //              Name:    SocketListen 
    72 //              Purpose:  
    73 //              Created: 2003/07/31 
    74 // 
    75 // -------------------------------------------------------------------------- 
    76 template<typename SocketType, int ListenBacklog = 128, typename SocketLockingType = _NoSocketLocking, int MaxMultiListenSockets = 16> 
    77 class SocketListen 
    78 { 
     33        std::auto_ptr<std::string> mapPipeName; 
     34        std::auto_ptr<OverlappedIO> mapOverlapConnect; 
     35        HANDLE mPipeHandle; 
     36 
    7937public: 
    8038        // Initialise 
    81         SocketListen() 
    82                 : mSocketHandle(-1) 
    83         { 
    84         } 
    85         // Close socket nicely 
    86         ~SocketListen() 
     39        WinNamedPipeListener() 
     40        : mPipeHandle(INVALID_HANDLE_VALUE) 
     41        { } 
     42 
     43private: 
     44        WinNamedPipeListener(const WinNamedPipeListener &rToCopy) 
     45        { /* forbidden */ } 
     46 
     47        HANDLE CreatePipeHandle(const std::string& rName) 
     48        { 
     49                std::string socket = WinNamedPipeStream::sPipeNamePrefix + 
     50                        rName; 
     51 
     52                HANDLE handle = CreateNamedPipeA(  
     53                        socket.c_str(),            // pipe name  
     54                        PIPE_ACCESS_DUPLEX |       // read/write access  
     55                        FILE_FLAG_OVERLAPPED,      // enabled overlapped I/O 
     56                        PIPE_TYPE_BYTE |           // message type pipe  
     57                        PIPE_READMODE_BYTE |       // message-read mode  
     58                        PIPE_WAIT,                 // blocking mode  
     59                        ListenBacklog + 1,         // max. instances   
     60                        4096,                      // output buffer size  
     61                        4096,                      // input buffer size  
     62                        NMPWAIT_USE_DEFAULT_WAIT,  // client time-out  
     63                        NULL);                     // default security attribute  
     64 
     65                if (handle == INVALID_HANDLE_VALUE) 
     66                { 
     67                        BOX_LOG_WIN_ERROR("Failed to create named pipe " << 
     68                                socket); 
     69                        THROW_EXCEPTION(ServerException, SocketOpenError) 
     70                } 
     71 
     72                return handle; 
     73        } 
     74 
     75public: 
     76        ~WinNamedPipeListener() 
    8777        { 
    8878                Close(); 
    8979        } 
    90 private: 
    91         SocketListen(const SocketListen &rToCopy) 
    92         { 
    93         } 
    94 public: 
    95  
    96         enum 
    97         { 
    98                 MaxMultipleListenSockets = MaxMultiListenSockets 
    99         }; 
    10080 
    10181        void Close() 
    10282        { 
    103                 if(mSocketHandle != -1) 
    104                 { 
    105 #ifdef WIN32 
    106                         if(::closesocket(mSocketHandle) == -1) 
    107 #else 
    108                         if(::close(mSocketHandle) == -1) 
    109 #endif 
    110                         { 
    111                                 BOX_LOG_SYS_ERROR("Failed to close network " 
    112                                         "socket"); 
    113                                 THROW_EXCEPTION(ServerException, 
    114                                         SocketCloseError) 
    115                         } 
    116                 } 
    117                 mSocketHandle = -1; 
     83                if (mPipeHandle != INVALID_HANDLE_VALUE) 
     84                { 
     85                        if (mapOverlapConnect.get()) 
     86                        { 
     87                                // outstanding connect in progress 
     88                                if (CancelIo(mPipeHandle) != TRUE) 
     89                                { 
     90                                        BOX_LOG_WIN_ERROR("Failed to cancel " 
     91                                                "outstanding connect request " 
     92                                                "on named pipe"); 
     93                                } 
     94 
     95                                mapOverlapConnect.reset(); 
     96                        } 
     97 
     98                        if (CloseHandle(mPipeHandle) != TRUE) 
     99                        { 
     100                                BOX_LOG_WIN_ERROR("Failed to close named pipe " 
     101                                        "handle"); 
     102                        } 
     103 
     104                        mPipeHandle = INVALID_HANDLE_VALUE; 
     105                } 
    118106        } 
    119107 
     
    121109        // 
    122110        // Function 
    123         //              Name:    SocketListen::Listen(int, char*, int) 
    124         //              Purpose: Initialises, starts the socket listening. 
     111        //              Name:    WinNamedPipeListener::Listen(std::string name) 
     112        //              Purpose: Initialises socket name 
    125113        //              Created: 2003/07/31 
    126114        // 
    127115        // ------------------------------------------------------------------ 
    128         void Listen(int Type, const char *Name, int Port = 0) 
    129         { 
    130                 if(mSocketHandle != -1) 
    131                 { 
    132                         THROW_EXCEPTION(ServerException, SocketAlreadyOpen); 
    133                 } 
    134                  
    135                 // Setup parameters based on type, looking up names if required 
    136                 int sockDomain = 0; 
    137                 SocketAllAddr addr; 
    138                 int addrLen = 0; 
    139                 Socket::NameLookupToSockAddr(addr, sockDomain, Type, Name, 
    140                         Port, addrLen); 
    141          
    142                 // Create the socket 
    143                 mSocketHandle = ::socket(sockDomain, SOCK_STREAM, 
    144                         0 /* let OS choose protocol */); 
    145                 if(mSocketHandle == -1) 
    146                 { 
    147                         BOX_LOG_SYS_ERROR("Failed to create a network socket"); 
    148                         THROW_EXCEPTION(ServerException, SocketOpenError) 
    149                 } 
    150                  
    151                 // Set an option to allow reuse (useful for -HUP situations!) 
    152 #ifdef WIN32 
    153                 if(::setsockopt(mSocketHandle, SOL_SOCKET, SO_REUSEADDR, "", 
    154                         0) == -1) 
    155 #else 
    156                 int option = true; 
    157                 if(::setsockopt(mSocketHandle, SOL_SOCKET, SO_REUSEADDR, 
    158                         &option, sizeof(option)) == -1) 
    159 #endif 
    160                 { 
    161                         BOX_LOG_SYS_ERROR("Failed to set socket options"); 
    162                         THROW_EXCEPTION(ServerException, SocketOpenError) 
    163                 } 
    164  
    165                 // Bind it to the right port, and start listening 
    166                 if(::bind(mSocketHandle, &addr.sa_generic, addrLen) == -1 
    167                         || ::listen(mSocketHandle, ListenBacklog) == -1) 
    168                 { 
    169                         // Dispose of the socket 
    170                         ::close(mSocketHandle); 
    171                         mSocketHandle = -1; 
    172                         THROW_EXCEPTION(ServerException, SocketBindError) 
    173                 }        
    174         } 
    175          
     116        void Listen(const std::string& rName) 
     117        { 
     118                Close(); 
     119                mapPipeName.reset(new std::string(rName)); 
     120                mPipeHandle = CreatePipeHandle(rName); 
     121        } 
     122 
    176123        // ------------------------------------------------------------------ 
    177124        // 
    178125        // Function 
    179         //              Name:    SocketListen::Accept(int) 
     126        //              Name:    WinNamedPipeListener::Accept(int) 
    180127        //              Purpose: Accepts a connection, returning a pointer to 
    181128        //                       a class of the specified type. May return a 
     
    186133        // 
    187134        // ------------------------------------------------------------------ 
    188         std::auto_ptr<SocketType> Accept(int Timeout = INFTIM, 
    189                 std::string *pLogMsg = 0) 
    190         { 
    191                 if(mSocketHandle == -1) 
     135        std::auto_ptr<WinNamedPipeStream> Accept(int Timeout = INFTIM, 
     136                const char* pLogMsgOut = NULL) 
     137        { 
     138                if(!mapPipeName.get()) 
    192139                { 
    193140                        THROW_EXCEPTION(ServerException, BadSocketHandle); 
    194141                } 
    195                  
    196                 // Do the accept, using the supplied locking type 
    197                 int sock; 
    198                 struct sockaddr addr; 
    199                 socklen_t addrlen = sizeof(addr); 
    200                 // BLOCK 
    201                 { 
    202                         SocketLockingType socklock(mSocketHandle); 
    203                          
    204                         if(!socklock.HaveLock()) 
    205                         { 
    206                                 // Didn't get the lock for some reason. 
    207                                 // Wait a while, then return nothing. 
    208                                 BOX_ERROR("Failed to get a lock on incoming " 
    209                                         "connection"); 
    210                                 ::sleep(1); 
    211                                 return std::auto_ptr<SocketType>(); 
    212                         } 
    213                          
    214                         // poll this socket 
    215                         struct pollfd p; 
    216                         p.fd = mSocketHandle; 
    217                         p.events = POLLIN; 
    218                         p.revents = 0; 
    219                         switch(::poll(&p, 1, Timeout)) 
    220                         { 
    221                         case -1: 
    222                                 // signal? 
    223                                 if(errno == EINTR) 
    224                                 { 
    225                                         BOX_ERROR("Failed to accept " 
    226                                                 "connection: interrupted by " 
    227                                                 "signal"); 
    228                                         // return nothing 
    229                                         return std::auto_ptr<SocketType>(); 
    230                                 } 
    231                                 else 
    232                                 { 
    233                                         BOX_LOG_SYS_ERROR("Failed to poll " 
    234                                                 "connection"); 
     142 
     143                BOOL connected = FALSE; 
     144                std::auto_ptr<WinNamedPipeStream> mapStream; 
     145 
     146                if (!mapOverlapConnect.get()) 
     147                { 
     148                        // start a new connect operation 
     149                        mapOverlapConnect.reset(new OverlappedIO()); 
     150                        connected = ConnectNamedPipe(mPipeHandle, 
     151                                &mapOverlapConnect->mOverlapped); 
     152 
     153                        if (connected == FALSE) 
     154                        { 
     155                                if (GetLastError() == ERROR_PIPE_CONNECTED) 
     156                                { 
     157                                        connected = TRUE; 
     158                                } 
     159                                else if (GetLastError() != ERROR_IO_PENDING) 
     160                                { 
     161                                        BOX_LOG_WIN_ERROR("Failed to connect " 
     162                                                "named pipe"); 
    235163                                        THROW_EXCEPTION(ServerException, 
    236                                                 SocketPollError) 
    237                                 } 
    238                                 break; 
    239                         case 0: // timed out 
    240                                 return std::auto_ptr<SocketType>(); 
    241                                 break; 
    242                         default:        // got some thing... 
    243                                 // control flows on... 
    244                                 break; 
    245                         } 
    246                          
    247                         sock = ::accept(mSocketHandle, &addr, &addrlen); 
    248                 } 
    249  
    250                 // Got socket (or error), unlock (implicit in destruction) 
    251                 if(sock == -1) 
    252                 { 
    253                         BOX_LOG_SYS_ERROR("Failed to accept connection"); 
    254                         THROW_EXCEPTION(ServerException, SocketAcceptError) 
    255                 } 
    256  
    257                 // Log it 
    258                 if(pLogMsg) 
    259                 { 
    260                         *pLogMsg = Socket::IncomingConnectionLogMessage(&addr, 
    261                                 addrlen); 
    262                 } 
    263                 else 
    264                 { 
    265                         // Do logging ourselves 
    266                         Socket::LogIncomingConnection(&addr, addrlen); 
    267                 } 
    268  
    269                 return std::auto_ptr<SocketType>(new SocketType(sock)); 
    270         } 
    271          
    272         // Functions to allow adding to WaitForEvent class, for efficient waiting 
    273         // on multiple sockets. 
    274 #ifdef HAVE_KQUEUE 
    275         // ------------------------------------------------------------------ 
    276         // 
    277         // Function 
    278         //              Name:    SocketListen::FillInKEevent 
    279         //              Purpose: Fills in a kevent structure for this socket 
    280         //              Created: 9/3/04 
    281         // 
    282         // ------------------------------------------------------------------ 
    283         void FillInKEvent(struct kevent &rEvent, int Flags = 0) const 
    284         { 
    285                 EV_SET(&rEvent, mSocketHandle, EVFILT_READ, 0, 0, 0, 
    286                         (void*)this); 
    287         } 
    288 #else 
    289         // ------------------------------------------------------------------ 
    290         // 
    291         // Function 
    292         //              Name:    SocketListen::FillInPoll 
    293         //              Purpose: Fills in the data necessary for a poll 
    294         //                       operation 
    295         //              Created: 9/3/04 
    296         // 
    297         // ------------------------------------------------------------------ 
    298         void FillInPoll(int &fd, short &events, int Flags = 0) const 
    299         { 
    300                 fd = mSocketHandle; 
    301                 events = POLLIN; 
    302         } 
    303 #endif 
    304          
    305 private: 
    306         int mSocketHandle; 
     164                                                SocketAcceptError); 
     165                                } 
     166                        } 
     167                } 
     168 
     169                if (connected == FALSE) 
     170                { 
     171                        // wait for connection 
     172                        DWORD result = WaitForSingleObject( 
     173                                mapOverlapConnect->mOverlapped.hEvent, 
     174                                (Timeout == INFTIM) ? INFINITE : Timeout); 
     175 
     176                        if (result == WAIT_OBJECT_0) 
     177                        { 
     178                                DWORD dummy; 
     179 
     180                                if (!GetOverlappedResult(mPipeHandle, 
     181                                        &mapOverlapConnect->mOverlapped, 
     182                                        &dummy, TRUE)) 
     183                                { 
     184                                        BOX_LOG_WIN_ERROR("Failed to get " 
     185                                                "overlapped connect result"); 
     186                                        THROW_EXCEPTION(ServerException, 
     187                                                SocketAcceptError); 
     188                                } 
     189                                 
     190                                connected = TRUE; 
     191                        } 
     192                        else if (result == WAIT_TIMEOUT) 
     193                        { 
     194                                return mapStream; // contains NULL 
     195                        } 
     196                        else if (result == WAIT_ABANDONED) 
     197                        { 
     198                                BOX_ERROR("Wait for named pipe connection " 
     199                                        "was abandoned by the system"); 
     200                                THROW_EXCEPTION(ServerException, 
     201                                        SocketAcceptError); 
     202                        } 
     203                        else if (result == WAIT_FAILED) 
     204                        { 
     205                                BOX_LOG_WIN_ERROR("Failed to wait for named " 
     206                                        "pipe connection"); 
     207                                THROW_EXCEPTION(ServerException, 
     208                                        SocketAcceptError); 
     209                        } 
     210                        else 
     211                        { 
     212                                BOX_ERROR("Failed to wait for named pipe " 
     213                                        "connection: unknown return code " << 
     214                                        result); 
     215                                THROW_EXCEPTION(ServerException, 
     216                                        SocketAcceptError); 
     217                        } 
     218                } 
     219 
     220                ASSERT(connected == TRUE); 
     221 
     222                mapStream.reset(new WinNamedPipeStream(mPipeHandle)); 
     223                mPipeHandle = CreatePipeHandle(*mapPipeName); 
     224                mapOverlapConnect.reset(); 
     225 
     226                return mapStream; 
     227        } 
    307228}; 
    308229 
    309230#include "MemLeakFindOff.h" 
    310231 
    311 #endif // SOCKETLISTEN__H 
    312  
     232#endif // WINNAMEDPIPELISTENER__H 
Note: See TracChangeset for help on using the changeset viewer.