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