1 /** 2 Copyright: Copyright (c) 2014-2018 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module netlib.packetmanagement; 8 9 import cbor; 10 import voxelman.log; 11 import derelict.enet.enet; 12 import voxelman.container.hash.set; 13 14 void loadEnet() 15 { 16 int err = enet_initialize(); 17 18 if (err != 0) 19 { 20 error("Error loading ENet library"); 21 return; 22 } 23 else 24 { 25 ENetVersion ever = enet_linked_version(); 26 infof("Loaded ENet library v%s.%s.%s", 27 ENET_VERSION_GET_MAJOR(ever), 28 ENET_VERSION_GET_MINOR(ever), 29 ENET_VERSION_GET_PATCH(ever)); 30 } 31 } 32 33 // packetData must contain data with packet id stripped off. 34 P unpackPacket(P)(ubyte[] packetData) 35 { 36 return decodeCborSingleDup!P(packetData); 37 } 38 39 P unpackPacketNoDup(P)(ubyte[] packetData) 40 { 41 return decodeCborSingle!P(packetData); 42 } 43 44 //version = Packet_Sniffing; 45 46 struct PacketSniffer(bool client) 47 { 48 private enum sideName = client ? "[CLIENT]" : "[SERVER]"; 49 HashSet!string disallowedPakets; 50 51 void onPacketCreate(string name, ubyte[] packetData) { 52 version (Packet_Sniffing) { 53 if (name !in disallowedPakets) 54 tracef(sideName ~ " create %s %(%02x%)", name, packetData); 55 } 56 } 57 58 void onPacketHandle(string name, ubyte[] packetData) { 59 version (Packet_Sniffing) { 60 if (name !in disallowedPakets) 61 tracef(sideName ~ " handle %s %(%02x%)", name, packetData); 62 } 63 } 64 } 65 66 mixin template PacketManagement(bool client) 67 { 68 static if (client) 69 alias PacketHandler = void delegate(ubyte[] packetData); 70 else 71 alias PacketHandler = void delegate(ubyte[] packetData, SessionId sessionId); 72 73 PacketSniffer!client sniffer; 74 75 static struct PacketInfo 76 { 77 string name; 78 PacketHandler handler; 79 size_t id; 80 } 81 82 // Used when handling packet based on its id. 83 PacketInfo*[] packetArray; 84 85 // Used to get packet id when sending packet. 86 PacketInfo*[TypeInfo] packetMap; 87 88 size_t packetId(P)() 89 { 90 return packetMap[typeid(P)].id; 91 } 92 93 string packetName(size_t packetId) 94 { 95 if (packetId >= packetArray.length) return "!UnknownPacket!"; 96 return packetArray[packetId].name; 97 } 98 99 void registerPacket(P)(PacketHandler handler = null, string packetName = P.stringof) 100 { 101 size_t newId = packetArray.length; 102 PacketInfo* pinfo = new PacketInfo(packetName, handler, newId); 103 packetArray ~= pinfo; 104 assert(typeid(P) !in packetMap); 105 packetMap[typeid(P)] = pinfo; 106 } 107 108 void registerPacketHandler(P)(PacketHandler handler) 109 { 110 import std.string : format; 111 assert(typeid(P) in packetMap, format("Packet '%s' was not registered", typeid(P))); 112 packetMap[typeid(P)].handler = handler; 113 } 114 115 bool handlePacket(size_t packetId, ubyte[] packetData, ENetPeer* peer) 116 { 117 if (packetId >= packetArray.length) 118 return false; // invalid packet 119 120 sniffer.onPacketHandle(packetArray[packetId].name, packetData); 121 122 auto handler = packetArray[packetId].handler; 123 if (handler is null) 124 return false; // handler is not set 125 126 static if (client) { 127 handler(packetData); 128 } else { 129 auto sessionId = SessionId(cast(size_t)peer.data); 130 handler(packetData, sessionId); 131 } 132 133 return true; 134 } 135 136 ubyte[] createPacket(P)(auto ref const(P) packet) 137 { 138 ubyte[] bufferTemp = buffer; 139 size_t size; 140 141 size_t pid = packetId!P; 142 size = encodeCbor(bufferTemp[], pid); 143 size += encodeCbor(bufferTemp[size..$], packet); 144 sniffer.onPacketCreate(packetArray[pid].name, bufferTemp[0..size]); 145 146 return bufferTemp[0..size]; 147 } 148 149 string[] packetNames() @property 150 { 151 import std.algorithm : map; 152 import std.array : array; 153 return packetArray.map!(a => a.name).array; 154 } 155 156 void printPacketMap() 157 { 158 foreach(i, packetInfo; packetArray) 159 { 160 tracef("% 2s: %s", i, packetInfo.name); 161 } 162 } 163 164 void shufflePackets() 165 { 166 import std.random; 167 randomShuffle(packetArray[1..$]); 168 foreach (i, packetInfo; packetArray) 169 packetInfo.id = i; 170 } 171 }