![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright (c) 2009-2010 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 #ifndef CAT_SPHYNX_SERVER_HPP 00030 #define CAT_SPHYNX_SERVER_HPP 00031 00032 #include <cat/net/SphynxTransport.hpp> 00033 #include <cat/threads/RWLock.hpp> 00034 #include <cat/threads/Thread.hpp> 00035 #include <cat/threads/WaitableFlag.hpp> 00036 #include <cat/net/SphynxCollexion.hpp> 00037 #include <cat/crypt/cookie/CookieJar.hpp> 00038 #include <cat/crypt/tunnel/KeyAgreementResponder.hpp> 00039 00040 namespace cat { 00041 00042 00043 namespace sphynx { 00044 00045 00046 /* 00047 Designed for server hardware with many processors. 00048 00049 In order to handle many users, the Sphynx server opens up a single UDP port 00050 to accept new connections, and several other UDP data ports for data. 00051 00052 For retransmissions and detecting link loss due to timeout, the server runs 00053 several additional threads that wake up periodically to perform timed tasks. 00054 00055 Server uses thread pool to receive packets on connect and worker ports, 00056 meaning that packets are processed by any free CPU as soon as they arrive. 00057 00058 Sphynx Server 00059 UDP Hello Port [1] 00060 + In case this thread spins constantly, only use one CPU for new 00061 connections since in-game experience is more important than login 00062 + Assigns users to a data port after handshake completes 00063 00064 UDP Data Ports [4 * (CPU Count)] 00065 + Spread users evenly across several ports since 00066 only one packet can be processed from a single port at a time 00067 + Any free CPU will process incoming packets as fast as possible 00068 00069 ServerTimer threads [(CPU Count) / 2] 00070 + In case these threads spin constantly, they only consume 00071 half of the CPU resources available 00072 + Wake up every X milliseconds according to Transport::TICK_RATE 00073 + Detect link loss due to silence timeout 00074 + Update transport layer 00075 + Retransmit lost messages 00076 + Re-evaluate bandwidth and transmit queued messages 00077 */ 00078 00079 00081 00082 // Derive from sphynx::Connexion and sphynx::Server to define server behavior 00083 class Connexion : public Transport, public ThreadRefObject 00084 { 00085 friend class Server; 00086 friend class Map; 00087 friend class ServerWorker; 00088 friend class ServerTimer; 00089 00090 public: 00091 Connexion(); 00092 virtual ~Connexion() {} 00093 00094 private: 00095 volatile u32 _destroyed; 00096 00097 u32 _key; // Map hash table index, unique for each active connection 00098 Connexion *_next_delete; 00099 ServerWorker *_server_worker; 00100 00101 u8 _first_challenge[64]; // First challenge seen from this client address 00102 u8 _cached_answer[128]; // Cached answer to this first challenge, to avoid eating server CPU time 00103 00104 private: 00105 // Return false to destroy this object 00106 bool Tick(ThreadPoolLocalStorage *tls, u32 now); 00107 00108 void OnRawData(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes); 00109 00110 virtual bool PostPacket(u8 *buffer, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes); 00111 00112 public: 00113 CAT_INLINE bool IsValid() { return _destroyed == 0; } 00114 CAT_INLINE u32 GetKey() { return _key; } 00115 00116 void Destroy(); 00117 00118 protected: 00119 NetAddr _client_addr; 00120 00121 // Last time a packet was received from this user -- for disconnect timeouts 00122 u32 _last_recv_tsc; 00123 00124 bool _seen_encrypted; 00125 AuthenticatedEncryption _auth_enc; 00126 00127 protected: 00128 virtual void OnConnect(ThreadPoolLocalStorage *tls) = 0; 00129 virtual void OnDestroy() = 0; 00130 virtual void OnTick(ThreadPoolLocalStorage *tls, u32 now) = 0; 00131 }; 00132 00133 00135 00136 class Map 00137 { 00138 protected: 00139 CAT_INLINE u32 hash_addr(const NetAddr &addr, u32 salt); 00140 00141 public: 00142 struct Slot 00143 { 00144 Connexion *connection; 00145 bool collision; 00146 Slot *next; 00147 }; 00148 00149 protected: 00150 u32 _hash_salt; 00151 CAT_ALIGNED(16) Slot _table[HASH_TABLE_SIZE]; 00152 RWLock _table_lock; 00153 00154 public: 00155 Map(); 00156 virtual ~Map(); 00157 00158 // Lookup client by address 00159 Connexion *Lookup(const NetAddr &addr); 00160 00161 // Lookup client by key 00162 Connexion *Lookup(u32 key); 00163 00164 // May return false if network address in Connexion is already in the map. 00165 // This averts a potential race condition but should never happen during 00166 // normal operation, so the Connexion allocation by caller won't be wasted. 00167 bool Insert(Connexion *conn); 00168 00169 // Destroy a list described by the 'next' member of Slot 00170 void DestroyList(Map::Slot *kill_list); 00171 00172 void Tick(ThreadPoolLocalStorage *tls); 00173 }; 00174 00175 00177 00178 class ServerWorker : public UDPEndpoint 00179 { 00180 friend class Map; 00181 00182 protected: 00183 Map *_conn_map; 00184 ServerTimer *_server_timer; 00185 00186 protected: 00187 volatile u32 _session_count; 00188 00189 public: 00190 ServerWorker(Map *conn_map, ServerTimer *server_timer); 00191 virtual ~ServerWorker(); 00192 00193 void IncrementPopulation(); 00194 void DecrementPopulation(); 00195 u32 GetPopulation() { return _session_count; } 00196 00197 protected: 00198 void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes); 00199 void OnWrite(u32 bytes) {} 00200 void OnClose(); 00201 }; 00202 00203 00205 00206 class ServerTimer : Thread 00207 { 00208 protected: 00209 Map *_conn_map; 00210 00211 protected: 00212 ServerWorker **_workers; 00213 int _worker_count; 00214 00215 protected: 00216 Map::Slot *_insert_head; 00217 Mutex _insert_lock; 00218 00219 protected: 00220 Map::Slot *_active_head; 00221 00222 public: 00223 ServerTimer(Map *conn_map, ServerWorker **workers, int worker_count); 00224 virtual ~ServerTimer(); 00225 00226 CAT_INLINE bool Valid() { return _worker_count > 0; } 00227 00228 public: 00229 void InsertSlot(Map::Slot *slot); 00230 00231 protected: 00232 CAT_INLINE void Tick(ThreadPoolLocalStorage *tls); 00233 bool ThreadFunction(void *param); 00234 00235 protected: 00236 static const int TIMER_THREAD_KILL_TIMEOUT = 10000; 00237 00238 WaitableFlag _kill_flag; 00239 }; 00240 00241 00243 00244 class Server : public UDPEndpoint 00245 { 00246 public: 00247 Server(); 00248 virtual ~Server(); 00249 00250 bool StartServer(ThreadPoolLocalStorage *tls, Port port, u8 *public_key, int public_bytes, u8 *private_key, int private_bytes, const char *session_key); 00251 00252 u32 GetTotalPopulation(); 00253 00254 static bool GenerateKeyPair(ThreadPoolLocalStorage *tls, const char *public_key_file, 00255 const char *private_key_file, u8 *public_key, 00256 int public_bytes, u8 *private_key, int private_bytes); 00257 00258 private: 00259 static const int SESSION_KEY_BYTES = 32; 00260 char _session_key[SESSION_KEY_BYTES]; 00261 00262 Port _server_port; 00263 Map _conn_map; 00264 00265 CookieJar _cookie_jar; 00266 KeyAgreementResponder _key_agreement_responder; 00267 u8 _public_key[PUBLIC_KEY_BYTES]; 00268 00269 static const int WORKER_LIMIT = 32; // Maximum number of workers 00270 ServerWorker **_workers; 00271 int _worker_count; 00272 00273 ServerTimer **_timers; 00274 int _timer_count; 00275 00276 private: 00277 ServerWorker *FindLeastPopulatedPort(); 00278 00279 void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes); 00280 void OnWrite(u32 bytes); 00281 void OnClose(); 00282 00283 protected: 00284 // Must return a new instance of your Connexion derivation 00285 virtual Connexion *NewConnexion() = 0; 00286 00287 // IP address filter: Return true to allow the connection to be made 00288 virtual bool AcceptNewConnexion(const NetAddr &src) = 0; 00289 00290 // Lookup client by key 00291 Connexion *Lookup(u32 key); 00292 }; 00293 00294 00295 } // namespace sphynx 00296 00297 00298 } // namespace cat 00299 00300 #endif // CAT_SPHYNX_SERVER_HPP
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.