Shadowrun: Awakened 29 September 2011 - Build 871
SphynxTransport.hpp
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net