![]() |
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_TRANSPORT_HPP 00030 #define CAT_SPHYNX_TRANSPORT_HPP 00031 00032 #include <cat/net/ThreadPoolSockets.hpp> 00033 #include <cat/threads/Mutex.hpp> 00034 #include <cat/crypt/tunnel/AuthenticatedEncryption.hpp> 00035 #include <cat/parse/BufferStream.hpp> 00036 00037 namespace cat { 00038 00039 00040 namespace sphynx { 00041 00042 00043 /* 00044 Based on what I have envisioned needing for my game, the following protocol is being 00045 used after spending weeks looking at alternatives and false-starts. It provides signaled 00046 disconnects, fragmentation, MTU discovery, time synchronization, three reliable ordered 00047 streams, one unordered reliable stream, and unreliable delivery. 00048 00049 The Transport object that implements a sender/receiver in the protocol requires 276 bytes 00050 of memory per server connection, plus 32 bytes per message fragment in flight, plus buffers 00051 for queued send/recv packets, and it keeps two mutexes for thread-safety. A lockless memory 00052 allocator is used to allocate all buffers except the fragmented message reassembly buffer. 00053 00054 Packet format on top of UDP header: 00055 00056 E { HDR(2 bytes)|ACK-ID(3 bytes)|DATA || ... || MAC(8 bytes) } || IV(3 bytes) 00057 00058 E: ChaCha-12 stream cipher. 00059 IV: Initialization vector used by security layer (Randomly initialized). 00060 MAC: Message authentication code used by security layer (HMAC-MD5). 00061 00062 HDR|ACK-ID|DATA: A message block inside the datagram. The HDR and ACK-ID 00063 fields employ compression to use as little as 1 byte together. 00064 00065 Each message follows the same format. A two-byte header followed by data: 00066 00067 --- Message Header (16 bits) --- 00068 0 1 2 3 4 5 6 7 8 9 a b c d e f 00069 <-- LSB ----------------- MSB --> 00070 | BHI |I|R| SOP | BLO | 00071 --------------------------------- 00072 00073 DATA_BYTES: BHI | BLO = Number of bytes in data part of message. 00074 If BHI = "111"b, the BLO byte is omitted and the receiver can 00075 assume that the rest of the packet contains just one message. 00076 I: 1=Followed by ACK-ID field. 0=ACK-ID is one higher than the last. 00077 R: 1=Reliable. 0=Unreliable. 00078 SOP: Super opcodes: 00079 0=Data (reliable or unreliable) 00080 1=Fragment (reliable) 00081 2=ACK (unreliable) 00082 3=MTU Probe (unreliable) 00083 4=MTU Set (unordered reliable) 00084 5=Time Ping (unreliable) 00085 6=Time Pong (unreliable) 00086 7=Disconnect (unreliable) 00087 00088 When the I bit is set, the data part is preceded by an ACK-ID, 00089 which is then applied to all following reliable messages. 00090 This additional size is NOT accounted for in the DATA_BYTES field. 00091 00092 When the FRAG opcode used for the first time in an ordered stream, 00093 the data part begins with a 16-bit Fragment Header. 00094 This additional size IS accounted for in the DATA_BYTES field. 00095 00096 Often times there is just one message in a datagram. To compress 00097 the header in this case, when BHI = 7 the receiver assumes that 00098 only one message is in the packet and uses the payload length to 00099 determine the length of the single message. BLO byte is omitted. 00100 00101 This *could* also be used on the final message in a cluster, 00102 but it cannot be done without a memcpy to cover up the extra 00103 header byte, which I don't consider worthwhile... 00104 00105 ------------- ACK-ID Field (24 bits) ------------ 00106 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 00107 <-- LSB --------------------------------- MSB --> 00108 | S | IDA (5) |C| IDB (7) |C| IDC (8) | 00109 ------------------------------------------------- 00110 00111 C: 1=Continues to next byte. 00112 S: 0=Unordered stream, 1-3: Ordered streams. 00113 ID: IDC | IDB | IDA (20 bits) 00114 00115 On retransmission, the ACK-ID field uses no compression 00116 since the receiver state cannot be determined. 00117 00118 --- Fragment Header (16 bits) --- 00119 0 1 2 3 4 5 6 7 8 9 a b c d e f 00120 <-- LSB ----------------- MSB --> 00121 | TOTAL_BYTES(16) | 00122 --------------------------------- 00123 00124 TOTAL_BYTES: Total bytes in data part of fragmented message, 00125 not including this header. 00126 */ 00127 00128 /* 00129 ACK message format: 00130 00131 Header: I=0, R=0, SOP=SOP_ACK 00132 Data: ROLLUP(3) || RANGE1 || RANGE2 || ... ROLLUP(3) || RANGE1 || RANGE2 || ... 00133 00134 ROLLUP = Next expected ACK-ID. Acknowledges every ID before this one. 00135 00136 RANGE1: 00137 START || END 00138 00139 START = First inclusive ACK-ID in a range to acknowledge. 00140 END = Final inclusive ACK-ID in a range to acknowledge. 00141 00142 Negative acknowledgment can be inferred from the holes in the RANGEs. 00143 00144 ------------ ROLLUP Field (24 bits) ------------- 00145 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 00146 <-- LSB --------------------------------- MSB --> 00147 |1| S | IDA (5) | IDB (8) | IDC (8) | 00148 ------------------------------------------------- 00149 00150 1: Indicates start of ROLLUP field. 00151 S: 0=Unordered stream, 1-3: Ordered streams. 00152 ID: IDC | IDB | IDA (21 bits) 00153 00154 ROLLUP is always 3 bytes since we cannot tell how far ahead the remote host is now. 00155 00156 --------- RANGE START Field (24 bits) ----------- 00157 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 00158 <-- LSB --------------------------------- MSB --> 00159 |0|E| IDA (5) |C| IDB (7) |C| IDC (8) | 00160 ------------------------------------------------- 00161 00162 0: Indicates start of RANGE field. 00163 C: 1=Continues to next byte. 00164 E: 1=Has end field. 0=One ID in range. 00165 ID: IDC | IDB | IDA (20 bits) + last ack id in message 00166 00167 ---------- RANGE END Field (24 bits) ------------ 00168 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 00169 <-- LSB --------------------------------- MSB --> 00170 | IDA (7) |C| IDB (7) |C| IDC (8) | 00171 ------------------------------------------------- 00172 00173 C: 1=Continues to next byte. 00174 ID: IDC | IDB | IDA (22 bits) + START.ID 00175 */ 00176 00177 class Connexion; 00178 class Map; 00179 class Server; 00180 class ServerWorker; 00181 class ServerTimer; 00182 class Client; 00183 class Transport; 00184 00185 #if defined(CAT_WORD_32) 00186 #define CAT_PACK_TRANSPORT_STATE_STRUCTURES /* For 32-bit version, this allows fragments to fit in 32 bytes */ 00187 #else // 64-bit version: 00188 //#define CAT_PACK_TRANSPORT_STATE_STRUCTURES /* No advantage for 64-bit version */ 00189 #endif 00190 00191 //#define CAT_TRANSPORT_DEBUG_LOGGING /* Enables info messages on console */ 00192 #define CAT_VERBOSE_VALIDATION /* Enables input error messages on console */ 00193 00194 // Protocol constants 00195 static const u32 PROTOCOL_MAGIC = 0xC47D0001; 00196 static const int PUBLIC_KEY_BYTES = 64; 00197 static const int PRIVATE_KEY_BYTES = 32; 00198 static const int CHALLENGE_BYTES = PUBLIC_KEY_BYTES; 00199 static const int ANSWER_BYTES = PUBLIC_KEY_BYTES*2; 00200 static const int HASH_TABLE_SIZE = 32768; // Power-of-2 00201 static const int HASH_TABLE_MASK = HASH_TABLE_SIZE - 1; 00202 static const int MAX_POPULATION = HASH_TABLE_SIZE / 2; 00203 00204 // (multiplier-1) divisible by all prime factors of table size 00205 // (multiplier-1) is a multiple of 4 if table size is a multiple of 4 00206 // These constants are from Press, Teukolsky, Vetterling and Flannery's 00207 // "Numerical Recipes in FORTRAN: The Art of Scientific Computing" 00208 static const u32 COLLISION_MULTIPLIER = 71*5861 * 4 + 1; 00209 static const u32 COLLISION_INCREMENTER = 1013904223; 00210 00211 // If multiplier changes, this needs to be recalculated (multiplicative inverse of above) 00212 static const u32 COLLISION_MULTINVERSE = 4276115653; 00213 static const u32 COLLISION_INCRINVERSE = 0 - COLLISION_INCREMENTER; 00214 00215 00216 // Handshake types 00217 enum HandshakeType 00218 { 00219 C2S_HELLO, 00220 S2C_COOKIE, 00221 C2S_CHALLENGE, 00222 S2C_ANSWER, 00223 S2C_ERROR 00224 }; 00225 00226 // Handshake errors 00227 enum HandshakeError 00228 { 00229 ERR_SERVER_FULL 00230 }; 00231 00232 // Stream modes 00233 enum StreamMode 00234 { 00235 STREAM_UNORDERED = 0, // Reliable, unordered stream 0 00236 STREAM_1 = 1, // Reliable, ordered stream 1 00237 STREAM_2 = 2, // Reliable, ordered stream 2 00238 STREAM_3 = 3 // Reliable, ordered stream 3 00239 }; 00240 00241 // Super Opcodes 00242 enum SuperOpcode 00243 { 00244 SOP_DATA, // 0=Data (reliable or unreliable) 00245 SOP_FRAG, // 1=Fragment (reliable) 00246 SOP_ACK, // 2=ACK (unreliable) 00247 SOP_MTU_PROBE, // 3=MTU Probe (unreliable) 00248 SOP_MTU_SET, // 4=MTU Set (unordered reliable) 00249 SOP_TIME_PING, // 5=Time Ping (unreliable) 00250 SOP_TIME_PONG, // 6=Time Pong (unreliable) 00251 SOP_DISCO, // 7=Disconnect (unreliable) 00252 }; 00253 00254 00256 00257 #if defined(CAT_PACK_TRANSPORT_STATE_STRUCTURES) 00258 #pragma pack(push) 00259 #pragma pack(1) 00260 #endif // CAT_PACK_TRANSPORT_STATE_STRUCTURES 00261 00262 // Receive state: Receive queue 00263 struct RecvQueue 00264 { 00265 static const u32 FRAG_FLAG = 0x80000000; 00266 static const u32 BYTE_MASK = 0x7fffffff; 00267 00268 RecvQueue *next; // Next in queue 00269 RecvQueue *prev; // Previous in queue 00270 u32 id; // Acknowledgment id 00271 u32 bytes; // High bit: Fragment? 00272 00273 // Message contents follow 00274 }; 00275 00276 // Send state: Send queue 00277 struct SendQueue 00278 { 00279 SendQueue *next; // Next in queue 00280 SendQueue *prev; // Previous in queue 00281 u32 ts_firstsend; // Millisecond-resolution timestamp when it was first sent 00282 u32 ts_lastsend; // Millisecond-resolution timestamp when it was last sent 00283 union 00284 { 00285 u32 sent_bytes; // In send queue: Number of sent bytes while fragmenting a large message 00286 u32 id; // In sent list: Acknowledgment id 00287 }; 00288 u16 bytes; // Data bytes 00289 u16 frag_count; // Number of fragments remaining to be delivered 00290 u16 sop; // Super opcode of message 00291 00292 // Message contents follow 00293 }; 00294 00295 struct SendFrag : public SendQueue 00296 { 00297 SendQueue *full_data; // Object containing message data 00298 u16 offset; // Fragment data offset 00299 }; 00300 00301 // Temporary send node structure, nestled in the encryption overhead of outgoing packets 00302 struct TempSendNode // Size <= 11 bytes = AuthenticatedEncryption::OVERHEAD_BYTES 00303 { 00304 static const u32 SINGLE_FLAG = 0x8000; 00305 static const u32 BYTE_MASK = 0x7fff; 00306 00307 TempSendNode *next; 00308 u16 negative_offset; // Number of bytes before this structure, and single flag 00309 }; 00310 00311 #if defined(CAT_PACK_TRANSPORT_STATE_STRUCTURES) 00312 #pragma pack(pop) 00313 #endif // CAT_PACK_TRANSPORT_STATE_STRUCTURES 00314 00315 class Transport 00316 { 00317 protected: 00318 static const u8 BHI_MASK = 7; 00319 static const u8 BHI_SINGLE_MESSAGE = 7; 00320 static const u8 I_MASK = 1 << 3; 00321 static const u8 R_MASK = 1 << 4; 00322 static const u32 SOP_SHIFT = 5; 00323 00324 static const u32 NUM_STREAMS = 4; // Number of reliable streams 00325 static const u32 MIN_RTT = 50; // Minimum milliseconds for RTT 00326 00327 static const int TIMEOUT_DISCONNECT = 15000; // 15 seconds 00328 static const int SILENCE_LIMIT = 9333; // 9.333 seconds: Time silent before sending a keep-alive (0-length unordered reliable message) 00329 00330 static const int TICK_RATE = 20; // 20 milliseconds 00331 00332 static const u32 MINIMUM_MTU = 576; // Dialup 00333 static const u32 MEDIUM_MTU = 1400; // Highspeed with unexpected overhead, maybe VPN 00334 static const u32 MAXIMUM_MTU = 1500; // Highspeed 00335 00336 static const u32 IPV6_OPTIONS_BYTES = 40; // TODO: Not sure about this 00337 static const u32 IPV6_HEADER_BYTES = 40 + IPV6_OPTIONS_BYTES; 00338 00339 static const u32 IPV4_OPTIONS_BYTES = 40; 00340 static const u32 IPV4_HEADER_BYTES = 20 + IPV4_OPTIONS_BYTES; 00341 00342 static const u32 UDP_HEADER_BYTES = 8; 00343 00344 static const u32 FRAG_THRESHOLD = 32; // Fragment if FRAG_THRESHOLD bytes would be in each fragment 00345 00346 static const u32 MAX_MESSAGE_DATALEN = 65535-1; // Maximum number of bytes in the data part of a message (-1 for the opcode) 00347 00348 protected: 00349 // Maximum transfer unit (MTU) in UDP payload bytes, excluding the IP and UDP headers and encryption overhead 00350 u32 _max_payload_bytes; 00351 00352 public: 00353 void InitializePayloadBytes(bool ip6); 00354 00355 protected: 00356 // Receive state: Next expected ack id to receive 00357 u32 _next_recv_expected_id[NUM_STREAMS]; 00358 00359 // Receive state: Synchronization objects 00360 volatile bool _got_reliable[NUM_STREAMS]; 00361 Mutex _recv_lock; // Just needs to protect writes OnDatagram() from messing up reads on tick 00362 00363 // Receive state: Fragmentation 00364 u8 *_fragment_buffer[NUM_STREAMS]; // Buffer for accumulating fragment 00365 u32 _fragment_length[NUM_STREAMS]; // Number of bytes in fragment buffer 00366 u32 _fragment_offset[NUM_STREAMS]; // Current write offset in buffer 00367 00368 static const u32 FRAG_MIN = 0; // Min bytes for a fragmented message 00369 static const u32 FRAG_MAX = 65535; // Max bytes for a fragmented message 00370 00371 // Receive state: Receive queue head 00372 RecvQueue *_recv_queue_head[NUM_STREAMS], *_recv_queue_tail[NUM_STREAMS]; 00373 00374 private: 00375 void RunQueue(ThreadPoolLocalStorage *tls, u32 ack_id, u32 stream); 00376 void QueueRecv(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes, u32 ack_id, u32 stream, u32 super_opcode); 00377 00378 protected: 00379 // Send state: Synchronization objects 00380 Mutex _send_lock; 00381 00382 // Send state: Next ack id to use 00383 u32 _next_send_id[NUM_STREAMS]; 00384 00385 // Send state: Estimated round-trip time 00386 u32 _rtt; // milliseconds 00387 00388 // Send state: Last rollup ack id from remote receiver 00389 u32 _send_next_remote_expected[NUM_STREAMS]; 00390 00391 // Send state: Combined writes 00392 u8 *_send_buffer; 00393 u32 _send_buffer_bytes; 00394 u32 _send_buffer_stream, _send_buffer_ack_id; // Used to compress ACK-ID by setting I=0 after the first reliable message 00395 u32 _send_buffer_msg_count; // Used to compress datagrams with a single message by omitting the header's BLO field 00396 00397 // Queue of messages that are waiting to be sent 00398 SendQueue *_send_queue_head[NUM_STREAMS], *_send_queue_tail[NUM_STREAMS]; 00399 00400 // List of messages that are waiting to be acknowledged 00401 SendQueue *_sent_list_head[NUM_STREAMS], *_sent_list_tail[NUM_STREAMS]; 00402 00403 bool _disconnected; 00404 00405 private: 00406 void TransmitQueued(); 00407 void Retransmit(u32 stream, SendQueue *node, u32 now); // Does not hold the send lock! 00408 void WriteACK(); 00409 void OnACK(u8 *data, u32 data_bytes); 00410 void OnMTUSet(u8 *data, u32 data_bytes); 00411 00412 public: 00413 Transport(); 00414 virtual ~Transport(); 00415 00416 public: 00417 // ata_bytes: Length of msg_data 00418 bool WriteUnreliable(u8 msg_opcode, const void *msg_data = 0, u32 data_bytes = 0); 00419 bool WriteReliable(StreamMode, u8 msg_opcode, const void *msg_data = 0, u32 data_bytes = 0, SuperOpcode super_opcode = SOP_DATA); 00420 void FlushWrite(); 00421 00422 protected: 00423 // Notify transport layer of disconnect to halt message processing 00424 CAT_INLINE void TransportDisconnected() { _disconnected = true; } 00425 CAT_INLINE bool IsDisconnected() { return _disconnected; } 00426 00427 void TickTransport(ThreadPoolLocalStorage *tls, u32 now); 00428 void OnDatagram(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes); 00429 00430 private: 00431 void OnFragment(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes, u32 stream); 00432 void CombineNextWrite(); 00433 00434 protected: 00435 // skip_bytes: Number of bytes to skip at the start of the buffer 00436 // buf_bytes and msg_bytes contain the skipped bytes 00437 virtual bool PostPacket(u8 *data, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes) = 0; 00438 virtual void OnTimestampDeltaUpdate(u32 rtt, s32 delta) {} 00439 virtual void OnMessage(ThreadPoolLocalStorage *tls, BufferStream msg, u32 bytes) = 0; 00440 virtual void OnDisconnect() = 0; 00441 00442 protected: 00443 bool PostMTUProbe(ThreadPoolLocalStorage *tls, u16 payload_bytes); 00444 bool PostTimePing(); 00445 bool PostTimePong(u32 client_ts); 00446 bool PostDisconnect(); 00447 }; 00448 00449 00450 } // namespace sphynx 00451 00452 00453 } // namespace cat 00454 00455 #endif // CAT_SPHYNX_TRANSPORT_HPP
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.