1
2
3
4 """
5 The container for packetloaders, which represents
6 a whole packet
7 """
8
9 from struct import Struct
10 import struct
11
12 from lacewing.packetloaders import client, server
13 from lacewing.baseloader import _BaseLoader
14 from lacewing.exceptions import OutOfData
15
16 SC_PACKET_TABLE = [
17
18 server.Response,
19 server.BinaryServerMessage,
20 server.BinaryChannelMessage,
21 server.BinaryPeerMessage,
22 server.BinaryServerChannelMessage,
23 server.ObjectServerMessage,
24 server.ObjectChannelMessage,
25 server.ObjectPeerMessage,
26 server.ObjectServerChannelMessage,
27 server.Peer,
28 server.UDPWelcome,
29 server.Ping
30 ]
31
32 CS_PACKET_TABLE = [
33
34 client.Request,
35 client.BinaryServerMessage,
36 client.BinaryChannelMessage,
37 client.BinaryPeerMessage,
38 client.ObjectServerMessage,
39 client.ObjectChannelMessage,
40 client.ObjectPeerMessage,
41 client.UDPHello,
42 client.ChannelMaster,
43 client.Pong
44 ]
45
46 for items in (CS_PACKET_TABLE, SC_PACKET_TABLE):
47 for index, item in enumerate(items):
48 item.id = index
49
50 HEADER_DATA = Struct('<BB')
51 FROM_ID = Struct('<H')
52 HEADER_DATA_UDP = Struct('<B')
53 SHORT_SIZE = Struct('<H')
54 INT_SIZE = Struct('<I')
55
57 """
58 The base packet.
59
60 @ivar loader: The loader that this packet contains
61 @ivar maxSize: The max size of a packet.
62 @ivar settings: Settings for this packet.
63 """
64 loader = None
65 fromId = None
66
67 - def read(self, data):
68 """
69 Load the specified data with the given settings.
70 @type data: buffer or str
71 """
72 datagram = self.settings.get('datagram', False)
73 packetSize = 0
74 if datagram:
75 headerByte, = HEADER_DATA_UDP.unpack_from(data)
76 if self.isClient:
77 self.fromId, = FROM_ID.unpack_from(data, 1)
78 packetData = buffer(data, 3)
79 else:
80 packetData = buffer(data, 1)
81 else:
82 if len(data) < 2:
83 raise OutOfData
84 headerByte, size = HEADER_DATA.unpack_from(data)
85 packetSize += HEADER_DATA.size
86
87 messageType = (headerByte & 0b11110000) >> 4
88 variant = headerByte & 0b00001111
89
90 if not datagram:
91 if size == 254:
92 size, = SHORT_SIZE.unpack_from(data, 2)
93 packetData = buffer(data, 4, size)
94 packetSize += 2 + size
95 elif size == 255:
96 size, = INT_SIZE.unpack_from(data, 2)
97 packetData = buffer(data, 6, size)
98 packetSize += 4 + size
99 else:
100 packetData = buffer(data, 2, size)
101 packetSize += size
102 if len(packetData) < size:
103 raise OutOfData
104 loaderClass = self.packetTable[messageType]
105 self.loader = self.new(loaderClass, packetData, variant = variant)
106 return packetSize
107
109 """
110 Generates the binary representation of the packet.
111 """
112 datagram = self.settings.get('datagram', False)
113 typeData = self.loader.generate()
114 variant = self.loader.settings.get('variant', 0)
115 headerByte = variant | (self.loader.id << 4)
116 if datagram:
117 if self.isClient:
118 fromData = FROM_ID.pack(self.fromId)
119 else:
120 fromData = ''
121 return HEADER_DATA_UDP.pack(headerByte) + fromData + typeData
122 else:
123 size = len(typeData)
124 sizeData = ''
125 if 65535 > size >= 254:
126 sizeData = SHORT_SIZE.pack(size)
127 size = 254
128 elif 4294967295 > size >= 65535:
129 sizeData = INT_SIZE.pack(size)
130 size = 255
131 return HEADER_DATA.pack(headerByte, size) + sizeData + typeData
132
136
140