+ if len(self.buffer) > MAXBUFFER:
+ # We are receiving junk. Let's drop it or we run out of memory.
+ log.warning("More than %d unparseable data, dropping", MAXBUFFER)
+ self.buffer = b""
+ msgs = []
+ while True:
+ framestart = self.buffer.find(b"xx")
+ if framestart == -1: # No frames, return whatever we have
+ break
+ if framestart > 0: # Should not happen, report
+ log.warning(
+ 'Undecodable data (%d) "%s" from fd %d (IMEI %s)',
+ framestart,
+ self.buffer[:framestart][:64].hex(),
+ self.sock.fileno(),
+ self.imei,
+ )
+ self.buffer = self.buffer[framestart:]
+ # At this point, buffer starts with a packet
+ if len(self.buffer) < 6: # no len and proto - cannot proceed
+ break
+ exp_end = self.buffer[2] + 3 # Expect '\r\n' here
+ frameend = 0
+ # Length field can legitimeely be much less than the
+ # length of the packet (e.g. WiFi positioning), but
+ # it _should not_ be greater. Still sometimes it is.
+ # Luckily, not by too much: by maybe two or three bytes?
+ # Do this embarrassing hack to avoid accidental match
+ # of some binary data in the packet against '\r\n'.
+ while True:
+ frameend = self.buffer.find(b"\r\n", frameend + 1)
+ if frameend == -1 or frameend >= (
+ exp_end - 3
+ ): # Found realistic match or none
+ break
+ if frameend == -1: # Incomplete frame, return what we have
+ break
+ packet = self.buffer[2:frameend]
+ self.buffer = self.buffer[frameend + 2 :]
+ if len(packet) < 2: # frameend comes too early
+ log.warning("Packet too short: %s", packet)
+ break
+ if proto_of_message(packet) == LOGIN.PROTO:
+ msg = parse_message(packet)
+ if isinstance(msg, LOGIN): # Can be unparseable
+ self.imei = msg.imei
+ log.info(
+ "LOGIN from fd %d (IMEI %s)",
+ self.sock.fileno(),
+ self.imei,
+ )
+ msgs.append((when, self.addr, packet))
+ return msgs