![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright (c) 2009 Christopher A. Taylor. All rights reserved. 00003 00004 Redistribution and use in source and binary forms, with or without 00005 modification, are permitted provided that the following conditions are met: 00006 00007 * Redistributions of source code must retain the above copyright notice, 00008 this list of conditions and the following disclaimer. 00009 * Redistributions in binary form must reproduce the above copyright notice, 00010 this list of conditions and the following disclaimer in the documentation 00011 and/or other materials provided with the distribution. 00012 * Neither the name of LibCat nor the names of its contributors may be used 00013 to endorse or promote products derived from this software without 00014 specific prior written permission. 00015 00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00019 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00020 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00021 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00022 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00023 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00024 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00025 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00026 POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00029 // TODO: Half-open connections can easily DoS the TCP server right now. 00030 // TODO: Port to Linux(eventfd) and BSD/MacOSX(kevent) 00031 00032 #ifndef CAT_THREAD_POOL_SOCKETS_HPP 00033 #define CAT_THREAD_POOL_SOCKETS_HPP 00034 00035 #include <cat/threads/ThreadPool.hpp> 00036 #include <cat/net/Sockets.hpp> 00037 00038 #if defined(CAT_MS_SOCKET_API) 00039 # include <MSWSock.h> 00040 # include <cat/port/WindowsInclude.hpp> 00041 #endif 00042 00043 namespace cat { 00044 00045 00046 /* 00047 Thread Pool Sockets library 00048 00049 Provides a framework for rapidly developing TCP/UDP server and client objects 00050 that make use of high performance APIs under various server and desktop 00051 operating systems. 00052 00053 All network events are processed by a thread pool managed by ThreadPool. 00054 */ 00055 00056 class TCPServer; 00057 class TCPConnection; 00058 class TCPClient; 00059 class UDPEndpoint; 00060 00061 00063 00064 // Generate a buffer to pass to Post() 00065 u8 *GetPostBuffer(u32 bytes); 00066 00067 void *ResizePostBuffer(void *buffer, u32 newBytes); 00068 00069 // Release a buffer provided by GetPostBuffer() 00070 // Note: Once the buffer is submitted to Post() this is unnecessary 00071 void ReleasePostBuffer(void *buffer); 00072 00073 00075 00076 // AcceptEx() OVERLAPPED structure 00077 struct AcceptExOverlapped 00078 { 00079 TypedOverlapped tov; 00080 Socket acceptSocket; 00081 00082 // Space pre-allocated to receive addresses 00083 // NOTE: This is not necessarily how the addresses are organized in memory 00084 struct 00085 { 00086 // Not necessarily an IPv6 address either! 00087 sockaddr_in6 addr[2]; 00088 u8 padding[2*16]; 00089 } addresses; 00090 00091 void Set(Socket s); 00092 }; 00093 00094 // WSARecvFrom() OVERLAPPED structure 00095 struct RecvFromOverlapped 00096 { 00097 TypedOverlapped tov; 00098 00099 // Not necessarily and IPv6 address, 00100 // but we allocate enough space for one 00101 int addrLen; 00102 sockaddr_in6 addr; 00103 00104 // data follows... 00105 00106 void Reset(); 00107 }; 00108 00109 00110 /* 00111 class TCPServer 00112 00113 Object that represents a TCP server bound to a single port 00114 00115 Overload InstantiateServerConnection() to subclass connections with the server 00116 */ 00117 class TCPServer : public ThreadRefObject 00118 { 00119 friend class TCPConnection; 00120 friend class ThreadPool; 00121 00122 public: 00123 TCPServer(); 00124 virtual ~TCPServer(); 00125 00126 bool ValidServer(); 00127 Port GetPort(); 00128 00129 bool Bind(Port port = 0); 00130 void Close(); 00131 00132 protected: 00133 virtual TCPConnection *InstantiateServerConnection() = 0; 00134 00135 private: 00136 Socket _socket; 00137 LPFN_ACCEPTEX _lpfnAcceptEx; 00138 LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs; 00139 LPFN_DISCONNECTEX _lpfnDisconnectEx; 00140 Port _port; 00141 00142 private: 00143 bool QueueAcceptEx(); 00144 bool QueueAccepts(); 00145 00146 void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped); 00147 }; 00148 00149 00150 /* 00151 class TCPConnection 00152 00153 Object that represents a TCPServer's connection from a TCPClient 00154 00155 Object is instantiated just before accepting a connection 00156 00157 DisconnectClient() : Disconnect the client 00158 PostToClient() : Send a message to the client 00159 ValidServerConnection() : Returns true iff the connection is valid 00160 00161 OnConnectFromClient() : Return false to deny this connection 00162 OnReadFromClient() : Return false to disconnect the client in response to a message 00163 OnWriteToClient() : Informs the derived class that data has been sent 00164 OnDisconectFromClient() : Informs the derived class that the client has disconnected 00165 */ 00166 class TCPConnection : public ThreadRefObject 00167 { 00168 friend class TCPServer; 00169 friend class ThreadPool; 00170 00171 public: 00172 TCPConnection(); 00173 virtual ~TCPConnection(); 00174 00175 bool ValidServerConnection(); 00176 00177 void DisconnectClient(); 00178 bool PostToClient(void *buffer, u32 bytes); 00179 00180 protected: 00181 virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect 00182 virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect 00183 virtual void OnWriteToClient(u32 bytes) = 0; 00184 virtual void OnDisconnectFromClient() = 0; 00185 00186 private: 00187 Socket _socket; 00188 LPFN_DISCONNECTEX _lpfnDisconnectEx; 00189 TypedOverlapped *_recvOv; 00190 volatile u32 _disconnecting; 00191 00192 private: 00193 bool AcceptConnection(Socket listenSocket, Socket acceptSocket, 00194 LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress, 00195 const NetAddr &remoteClientAddress); 00196 00197 bool QueueWSARecv(); 00198 void OnWSARecvComplete(int error, u32 bytes); 00199 00200 bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes); 00201 void OnWSASendComplete(int error, u32 bytes); 00202 00203 bool QueueDisconnectEx(); 00204 void OnDisconnectExComplete(int error); 00205 }; 00206 00207 00208 /* 00209 class TCPClient 00210 00211 Object that represents a TCPClient bound to a single port 00212 00213 ValidClient() : Returns true iff the client socket is valid 00214 00215 Connect() : Connects to the given address 00216 DisconnectServer() : Disconnects from the server 00217 PostToServer() : Send a message to the server (will fail if not connected) 00218 00219 OnConnectToServer() : Called when connection is accepted 00220 OnReadFromServer() : Return false to disconnect the server in response to data 00221 OnWriteToServer() : Informs the derived class that data has been sent 00222 OnDisconnectFromServer() : Informs the derived class that the server has disconnected 00223 */ 00224 class TCPClient : public ThreadRefObject 00225 { 00226 friend class ThreadPool; 00227 00228 public: 00229 TCPClient(); 00230 virtual ~TCPClient(); 00231 00232 bool ValidClient(); 00233 00234 bool Connect(const NetAddr &remoteServerAddress); 00235 void DisconnectServer(); 00236 bool PostToServer(void *buffer, u32 bytes); 00237 00238 protected: 00239 virtual void OnConnectToServer() = 0; 00240 virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect 00241 virtual void OnWriteToServer(u32 bytes) = 0; 00242 virtual void OnDisconnectFromServer() = 0; 00243 00244 private: 00245 Socket _socket; 00246 TypedOverlapped *_recvOv; 00247 volatile u32 _disconnecting; 00248 bool _ipv6; 00249 00250 private: 00251 bool QueueConnectEx(const NetAddr &remoteServerAddress); 00252 void OnConnectExComplete(int error); 00253 00254 bool QueueWSARecv(); 00255 void OnWSARecvComplete(int error, u32 bytes); 00256 00257 bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes); 00258 void OnWSASendComplete(int error, u32 bytes); 00259 00260 bool QueueDisconnectEx(); 00261 void OnDisconnectExComplete(int error); 00262 }; 00263 00264 00265 /* 00266 class TCPClientQueued 00267 00268 Base class for a TCP client that needs to queue up data for sending before 00269 a connection has been established. e.g. Uplink for a proxy server. 00270 00271 PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages. 00272 */ 00273 class TCPClientQueued : public TCPClient 00274 { 00275 private: 00276 volatile bool _queuing; 00277 00278 Mutex _queueLock; 00279 void *_queueBuffer; 00280 u32 _queueBytes; 00281 00282 protected: 00283 void PostQueuedToServer(); 00284 00285 public: 00286 TCPClientQueued(); 00287 virtual ~TCPClientQueued(); 00288 00289 bool PostToServer(void *buffer, u32 bytes); 00290 }; 00291 00292 00293 /* 00294 class UDPEndpoint 00295 00296 Object that represents a UDP endpoint bound to a single port 00297 */ 00298 class UDPEndpoint : public ThreadRefObject 00299 { 00300 friend class ThreadPool; 00301 00302 public: 00303 UDPEndpoint(); 00304 virtual ~UDPEndpoint(); 00305 00306 bool Valid(); 00307 Port GetPort(); 00308 00309 // Is6() result is only valid AFTER Bind() 00310 CAT_INLINE bool Is6() { return _ipv6; } 00311 00312 // For servers: Bind() with ignoreUnreachable = true ((default)) 00313 // For clients: Bind() with ignoreUnreachable = false and call this 00314 // after the first packet from the server is received. 00315 bool IgnoreUnreachable(); 00316 00317 void Close(); // Invalidates this object 00318 bool Bind(Port port = 0, bool ignoreUnreachable = true); 00319 bool QueueWSARecvFrom(); 00320 00321 // If Is6() == true, the address must be promoted to IPv6 00322 // before calling Post() with addr.PromoteTo6() 00323 bool Post(const NetAddr &addr, void *data, u32 bytes); 00324 00325 protected: 00326 virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close 00327 virtual void OnWrite(u32 bytes) = 0; 00328 virtual void OnClose() = 0; 00329 virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid 00330 00331 private: 00332 Socket _socket; 00333 Port _port; 00334 volatile u32 _closing; 00335 bool _ipv6; 00336 00337 private: 00338 bool QueueWSARecvFrom(RecvFromOverlapped *recvOv); 00339 void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes); 00340 00341 bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes); 00342 void OnWSASendToComplete(int error, u32 bytes); 00343 }; 00344 00345 00346 } // namespace cat 00347 00348 #endif // CAT_THREAD_POOL_SOCKETS_HPP
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.