- self.buffer += packet
- # implement framing properly
- msg = handle_packet(packet, self.clntaddr, when)
- self.buffer = self.buffer[len(packet):]
- if isinstance(msg, LOGIN):
- self.imei = msg.imei
- return msg
+ self.buffer += segment
+ 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 "%s" from fd %d (IMEI %s)',
+ self.buffer[:framestart].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)
+ if frameend >= (exp_end - 3): # Found realistic match
+ break
+ if frameend == -1: # Incomplete frame, return what we have
+ break
+ packet = self.buffer[2:frameend]
+ self.buffer = self.buffer[frameend + 2 :]
+ if proto_of_message(packet) == LOGIN.PROTO:
+ self.imei = parse_message(packet).imei
+ log.info(
+ "LOGIN from fd %d (IMEI %s)", self.sock.fileno(), self.imei
+ )
+ msgs.append((when, self.addr, packet))
+ return msgs