Changeset 2313
- Timestamp:
- 03/10/2008 23:39:59 (4 years ago)
- Location:
- box/trunk/lib/server
- Files:
-
- 1 added
- 1 copied
-
OverlappedIO.h (added)
-
WinNamedPipeListener.h (copied) (copied from box/trunk/lib/server/SocketListen.h) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
box/trunk/lib/server/WinNamedPipeListener.h
r2127 r2313 2 2 // 3 3 // 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 33 17 #include "ServerException.h" 34 18 … … 38 22 // 39 23 // 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 // -------------------------------------------------------------------------- 29 template<int ListenBacklog = 128> 30 class WinNamedPipeListener 46 31 { 47 public:48 _NoSocketLocking(int sock)49 {50 }51 52 ~_NoSocketLocking()53 {54 }55 56 bool HaveLock()57 {58 return true;59 }60 61 32 private: 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 79 37 public: 80 38 // Initialise 81 SocketListen() 82 : mSocketHandle(-1) 83 { 84 } 85 // Close socket nicely 86 ~SocketListen() 39 WinNamedPipeListener() 40 : mPipeHandle(INVALID_HANDLE_VALUE) 41 { } 42 43 private: 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 75 public: 76 ~WinNamedPipeListener() 87 77 { 88 78 Close(); 89 79 } 90 private:91 SocketListen(const SocketListen &rToCopy)92 {93 }94 public:95 96 enum97 {98 MaxMultipleListenSockets = MaxMultiListenSockets99 };100 80 101 81 void Close() 102 82 { 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 } 118 106 } 119 107 … … 121 109 // 122 110 // 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 125 113 // Created: 2003/07/31 126 114 // 127 115 // ------------------------------------------------------------------ 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 176 123 // ------------------------------------------------------------------ 177 124 // 178 125 // Function 179 // Name: SocketListen::Accept(int)126 // Name: WinNamedPipeListener::Accept(int) 180 127 // Purpose: Accepts a connection, returning a pointer to 181 128 // a class of the specified type. May return a … … 186 133 // 187 134 // ------------------------------------------------------------------ 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()) 192 139 { 193 140 THROW_EXCEPTION(ServerException, BadSocketHandle); 194 141 } 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"); 235 163 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 } 307 228 }; 308 229 309 230 #include "MemLeakFindOff.h" 310 231 311 #endif // SOCKETLISTEN__H 312 232 #endif // WINNAMEDPIPELISTENER__H
Note: See TracChangeset
for help on using the changeset viewer.
