1 /*
2  * MsgTrans - Message Transport Framework for DLang. Based on TCP, WebSocket, UDP transmission protocol.
3  *
4  * Copyright (C) 2019 HuntLabs
5  *
6  * Website: https://www.msgtrans.org
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module msgtrans.PacketHeader;
13 
14 import msgtrans.MessageBuffer;
15 import std.bitmanip;
16 import std.format;
17 import std.stdint;
18 import hunt.logging;
19 /* -------------------------------------------------------------------------- */
20 /*                                  protocol                                  */
21 /* -------------------------------------------------------------------------- */
22 
23 enum int ID_FIELD_LENGTH = uint.sizeof;
24 enum int LENGTH_FIELD_LENGTH = uint.sizeof;
25 enum int COMPRESSION_FIELD_LENGTH = byte.sizeof;
26 // enum int RESERVED_FILED_LENGTH = -;
27 enum int EXTENSION_FIELD_LENGTH = uint.sizeof;
28 enum int PACKET_HEADER_LENGTH = 16;
29 
30 enum int MAX_PACKET_SIZE = 4 * 1024 * 1024; // 4M
31 
32 // Used to filter the invalid data
33 __gshared uint[] AvaliableMessageIds = [];
34 
35 /* -------------------------------------------------------------------------- */
36 
37 // enum SERIALIZATION_TYPE : ushort {
38 //     NONE,
39 //     JSON,
40 //     MSGPACK,
41 //     PROTOBUF,
42 //     FLATBUFFERS
43 // }
44 
45 // enum ENCRYPT_TYPE : ushort {
46 //     NONE,
47 //     ACE_256,
48 //     ACE_512
49 // }
50 
51 // enum COMPACTION_TYPE : ushort {
52 //     NONE,
53 //     L4,
54 //     ZIP,
55 //     GZIP,
56 //     LZMA
57 // }
58 
59 /**
60  *
61  */
62 class PacketHeader
63 {
64 
65     private
66     {
67         // Message ID
68         uint _messageID = 0;
69 
70         // Message data length
71         uint _messageLength = 0;
72 
73         ubyte _compressionType;
74 
75         uint _extendLength;
76         // Serialization type including json, protobuf, msgpack, flatbuffers and more
77         // ushort _serializationType = 0;
78 
79         // used encrypt algorithm, 0 is none
80         // ushort _encryptType = 0;
81 
82         // used compaction algorithm, 0 is none
83         // ushort _compactionType = 0;
84     }
85 
86     this(uint id, uint length, uint extlen)
87     {
88         _messageID = id;
89         _messageLength = length;
90         //_compressionType = compr;
91         _extendLength = extlen;
92     }
93 
94     static PacketHeader parse(ubyte[] data)
95     {
96         // if (data.length < PACKET_HEADER_LENGTH)
97         // {
98         //     return null;
99         // }
100         // NOTE: Byte ordering is big endian.
101         version(HUNT_DEBUG) logInfof("ID_FIELD_LENGTH: %d",ID_FIELD_LENGTH);
102         ubyte[ID_FIELD_LENGTH] idBytes = data[0..ID_FIELD_LENGTH];
103         uint id = bigEndianToNative!(uint)(idBytes);
104         if(id == 0) {
105             return null;
106         }
107 
108         enum LengthStart = ID_FIELD_LENGTH;
109         enum LengthEnd = ID_FIELD_LENGTH + LENGTH_FIELD_LENGTH;
110         ubyte[LENGTH_FIELD_LENGTH] lengthBytes = data[LengthStart..LengthEnd];
111         uint length = bigEndianToNative!uint(lengthBytes);
112 
113 
114         enum LengthCompression  = LengthEnd +  COMPRESSION_FIELD_LENGTH;
115         ubyte[COMPRESSION_FIELD_LENGTH] compression = data[LengthEnd .. LengthCompression];
116         ubyte ucompre = (bigEndianToNative!ubyte(compression));
117 
118         enum LengthExtend = LengthCompression + EXTENSION_FIELD_LENGTH;
119         ubyte[EXTENSION_FIELD_LENGTH] ex = data[LengthCompression .. LengthExtend];
120         uint extendLen = bigEndianToNative!uint(ex);
121 
122         return new PacketHeader(id, length ,extendLen);
123     }
124 
125     static ubyte[] encode(MessageBuffer message) {
126         ubyte[ID_FIELD_LENGTH] h0 = nativeToBigEndian(message.id);
127         ubyte[LENGTH_FIELD_LENGTH] h1 = nativeToBigEndian(cast(int)(message.data.length));
128         ubyte[COMPRESSION_FIELD_LENGTH] h2 = message.compression;
129         ubyte[EXTENSION_FIELD_LENGTH] h3;
130         if (message.hasExtend)
131         {
132           h3 = nativeToBigEndian(message.extendLength);
133         }else
134         {
135           h3 = nativeToBigEndian(0);
136         }
137 
138 
139         ubyte[] buffer = new ubyte[PACKET_HEADER_LENGTH];
140         buffer[0..ID_FIELD_LENGTH] = h0[];
141 
142         int lengthStart = ID_FIELD_LENGTH;
143         int lengthEnd1 = lengthStart + LENGTH_FIELD_LENGTH;
144 
145         buffer[lengthStart .. lengthEnd1] = h1[];
146 
147         int lengthEnd2 = lengthEnd1 + COMPRESSION_FIELD_LENGTH;
148 
149         buffer[lengthEnd1 .. lengthEnd2] = h2[];
150 
151         int lengthEnd3 = lengthEnd2 + EXTENSION_FIELD_LENGTH;
152 
153         buffer[lengthEnd2 .. lengthEnd3] = h3[];
154 
155         return buffer;
156     }
157 
158     ubyte[] data()
159     {
160         ubyte[ID_FIELD_LENGTH] h0 = nativeToBigEndian(_messageID);
161         ubyte[LENGTH_FIELD_LENGTH] h1 = nativeToBigEndian(_messageLength);
162 
163         ubyte[] data = h0 ~ h1;
164         if (data.length < PACKET_HEADER_LENGTH)
165         {
166             ubyte[] h3 = new ubyte[PACKET_HEADER_LENGTH - data.length];
167             return data ~ h3;
168         }
169 
170         return data;
171     }
172 
173     uint messageId()
174     {
175         return _messageID;
176     }
177 
178     long messageLength()
179     {
180         return _messageLength;
181     }
182 
183     uint extendLength()
184     {
185         return _extendLength;
186     }
187 
188     override string toString() {
189         return format("id: %d, length: %d  _extendLength: %d", _messageID, _messageLength,_extendLength);
190     }
191 }