@@ -42,8 +42,30 @@ async def parsePacketPayload(self, payload, log_data={}):
4242 Returns :
4343 completed log_data
4444 """
45+ # Minimum viable payload is 2 bytes (1 header + 1 path_byte) for a
46+ # direct route. Anything shorter is provably broken — for example,
47+ # the LOG_DATA branch in reader.py only requires `len(data) > 3`,
48+ # which means a 4-byte LOG_DATA frame produces a 1-byte payload
49+ # here, and `path_byte = pbuf.read(1)[0]` further down would raise
50+ # IndexError on the empty buffer. Populate sentinel values so the
51+ # caller's downstream `log_data['route_type']` etc. lookups don't
52+ # KeyError, then return early.
53+ if len (payload ) < 2 :
54+ logger .debug (f"parsePacketPayload: payload too short ({ len (payload )} bytes < 2), returning sentinel log_data" )
55+ log_data ["route_type" ] = - 1
56+ log_data ["route_typename" ] = "UNK"
57+ log_data ["payload_type" ] = - 1
58+ log_data ["payload_typename" ] = "UNK"
59+ log_data ["payload_ver" ] = 0
60+ log_data ["path_len" ] = 0
61+ log_data ["path_hash_size" ] = 1
62+ log_data ["path" ] = ""
63+ log_data ["pkt_payload" ] = b""
64+ log_data ["pkt_hash" ] = 0
65+ return log_data
66+
4567 pbuf = io .BytesIO (payload )
46-
68+
4769 header = pbuf .read (1 )[0 ]
4870 route_type = header & 0x03
4971 payload_type = (header & 0x3c ) >> 2
@@ -128,7 +150,7 @@ async def parsePacketPayload(self, payload, log_data={}):
128150 uncrypted = cipher .decrypt (msg )
129151 timestamp = int .from_bytes (uncrypted [0 :4 ], "little" , signed = False )
130152 attempt = uncrypted [4 ] & 3
131- txt_type = int .from_bytes (uncrypted [4 :4 ], "little" , signed = False ) >> 2
153+ txt_type = int .from_bytes (uncrypted [4 :5 ], "little" , signed = False ) >> 2
132154 message = uncrypted [5 :].strip (b"\0 " )
133155 msg_hash = int .from_bytes (SHA256 .new (timestamp .to_bytes (4 , "little" , signed = False ) + message ).digest ()[0 :4 ], "little" , signed = False )
134156 log_data ["message" ] = message .decode ("utf-8" , "ignore" )
@@ -149,39 +171,42 @@ async def parsePacketPayload(self, payload, log_data={}):
149171 del self .channels_log [:25 ]
150172
151173 elif not payload is None and payload_type == 0x04 : # Advert
152- pk_buf = io .BytesIO (pkt_payload )
153- adv_key = pk_buf .read (32 ).hex ()
154- adv_timestamp = int .from_bytes (pk_buf .read (4 ), "little" , signed = False )
155- signature = pk_buf .read (64 ).hex ()
156- flags = pk_buf .read (1 )[0 ]
157- adv_type = flags & 0x0F
158- adv_lat = None
159- adv_lon = None
160- adv_feat1 = None
161- adv_feat2 = None
162- if flags & 0x10 > 0 : #has location
163- adv_lat = int .from_bytes (pk_buf .read (4 ), "little" , signed = True )/ 1000000.0
164- adv_lon = int .from_bytes (pk_buf .read (4 ), "little" , signed = True )/ 1000000.0
165- if flags & 0x20 > 0 : #has feature1
166- adv_feat1 = pk_buf .read (2 ).hex ()
167- if flags & 0x40 > 0 : #has feature2
168- adv_feat2 = pk_buf .read (2 ).hex ()
169- if flags & 0x80 > 0 : #has name
170- adv_name = pk_buf .read ().decode ("utf-8" , "ignore" ).strip ("\x00 " )
171- log_data ["adv_name" ] = adv_name
172-
173- log_data ["adv_key" ] = adv_key
174- log_data ["adv_timestamp" ] = adv_timestamp
175- log_data ["signature" ] = signature
176- log_data ["adv_flags" ] = flags
177- log_data ["adv_type" ] = adv_type
178- if not adv_lat is None :
179- log_data ["adv_lat" ] = adv_lat
180- if not adv_lon is None :
181- log_data ["adv_lon" ] = adv_lon
182- if not adv_feat1 is None :
183- log_data ["adv_feat1" ] = adv_feat1
184- if not adv_feat2 is None :
185- log_data ["adv_feat2" ] = adv_feat2
174+ try :
175+ pk_buf = io .BytesIO (pkt_payload )
176+ adv_key = pk_buf .read (32 ).hex ()
177+ adv_timestamp = int .from_bytes (pk_buf .read (4 ), "little" , signed = False )
178+ signature = pk_buf .read (64 ).hex ()
179+ flags = pk_buf .read (1 )[0 ]
180+ adv_type = flags & 0x0F
181+ adv_lat = None
182+ adv_lon = None
183+ adv_feat1 = None
184+ adv_feat2 = None
185+ if flags & 0x10 > 0 : #has location
186+ adv_lat = int .from_bytes (pk_buf .read (4 ), "little" , signed = True )/ 1000000.0
187+ adv_lon = int .from_bytes (pk_buf .read (4 ), "little" , signed = True )/ 1000000.0
188+ if flags & 0x20 > 0 : #has feature1
189+ adv_feat1 = pk_buf .read (2 ).hex ()
190+ if flags & 0x40 > 0 : #has feature2
191+ adv_feat2 = pk_buf .read (2 ).hex ()
192+ if flags & 0x80 > 0 : #has name
193+ adv_name = pk_buf .read ().decode ("utf-8" , "ignore" ).strip ("\x00 " )
194+ log_data ["adv_name" ] = adv_name
195+
196+ log_data ["adv_key" ] = adv_key
197+ log_data ["adv_timestamp" ] = adv_timestamp
198+ log_data ["signature" ] = signature
199+ log_data ["adv_flags" ] = flags
200+ log_data ["adv_type" ] = adv_type
201+ if not adv_lat is None :
202+ log_data ["adv_lat" ] = adv_lat
203+ if not adv_lon is None :
204+ log_data ["adv_lon" ] = adv_lon
205+ if not adv_feat1 is None :
206+ log_data ["adv_feat1" ] = adv_feat1
207+ if not adv_feat2 is None :
208+ log_data ["adv_feat2" ] = adv_feat2
209+ except (IndexError , ValueError ) as e :
210+ logger .debug (f"parsePacketPayload: malformed ADVERT payload ({ type (e ).__name__ } : { e } ), len={ len (pkt_payload )} " )
186211
187212 return log_data
0 commit comments