def read_message(self):
header = self.read_all(self.__block_size_in, check_rekey=True)<EOL>if self.__block_engine_in != None:<EOL><INDENT>header = self.__block_engine_in.decrypt(header)<EOL><DEDENT>if self.__dump_packets:<EOL><INDENT>self._log(DEBUG, util.format_binary(header, '<STR_LIT>'));<EOL><DEDENT>packet_size = struct.unpack('<STR_LIT>', header[:<NUM_LIT:4>])[<NUM_LIT:0>]<EOL>leftover = header[<NUM_LIT:4>:]<EOL>if (packet_size - len(leftover)) % self.__block_size_in != <NUM_LIT:0>:<EOL><INDENT>raise SSHException('<STR_LIT>')<EOL><DEDENT>buf = self.read_all(packet_size + self.__mac_size_in - len(leftover))<EOL>packet = buf[:packet_size - len(leftover)]<EOL>post_packet = buf[packet_size - len(leftover):]<EOL>if self.__block_engine_in != None:<EOL><INDENT>packet = self.__block_engine_in.decrypt(packet)<EOL><DEDENT>if self.__dump_packets:<EOL><INDENT>self._log(DEBUG, util.format_binary(packet, '<STR_LIT>'));<EOL><DEDENT>packet = leftover + packet<EOL>if self.__mac_size_in > <NUM_LIT:0>:<EOL><INDENT>mac = post_packet[:self.__mac_size_in]<EOL>mac_payload = struct.pack('<STR_LIT>', self.__sequence_number_in, packet_size) + packet<EOL>my_mac = compute_hmac(self.__mac_key_in, mac_payload, self.__mac_engine_in)[:self.__mac_size_in]<EOL>if my_mac != mac:<EOL><INDENT>raise SSHException('<STR_LIT>')<EOL><DEDENT><DEDENT>padding = ord(packet[<NUM_LIT:0>])<EOL>payload = packet[<NUM_LIT:1>:packet_size - padding]<EOL>if self.__dump_packets:<EOL><INDENT>self._log(DEBUG, '<STR_LIT>' % (packet_size, padding))<EOL><DEDENT>if self.__compress_engine_in is not None:<EOL><INDENT>payload = self.__compress_engine_in(payload)<EOL><DEDENT>msg = Message(payload[<NUM_LIT:1>:])<EOL>msg.seqno = self.__sequence_number_in<EOL>self.__sequence_number_in = (self.__sequence_number_in + <NUM_LIT:1>) & <NUM_LIT><EOL>raw_packet_size = packet_size + self.__mac_size_in + <NUM_LIT:4><EOL>self.__received_bytes += raw_packet_size<EOL>self.__received_packets += <NUM_LIT:1><EOL>if self.__need_rekey:<EOL><INDENT>self.__received_bytes_overflow += raw_packet_size<EOL>self.__received_packets_overflow += <NUM_LIT:1><EOL>if (self.__received_packets_overflow >= self.REKEY_PACKETS_OVERFLOW_MAX) or(self.__received_bytes_overflow >= self.REKEY_BYTES_OVERFLOW_MAX):<EOL><INDENT>raise SSHException('<STR_LIT>')<EOL><DEDENT><DEDENT>elif (self.__received_packets >= self.REKEY_PACKETS) or(self.__received_bytes >= self.REKEY_BYTES):<EOL><INDENT>self._log(DEBUG, '<STR_LIT>' %<EOL>(self.__received_packets, self.__received_bytes))<EOL>self.__received_bytes_overflow = <NUM_LIT:0><EOL>self.__received_packets_overflow = <NUM_LIT:0><EOL>self._trigger_rekey()<EOL><DEDENT>cmd = ord(payload[<NUM_LIT:0>])<EOL>if cmd in MSG_NAMES:<EOL><INDENT>cmd_name = MSG_NAMES[cmd]<EOL><DEDENT>else:<EOL><INDENT>cmd_name = '<STR_LIT>' % cmd<EOL><DEDENT>if self.__dump_packets:<EOL><INDENT>self._log(DEBUG, '<STR_LIT>' % (cmd_name, len(payload)))<EOL><DEDENT>return cmd, msg<EOL>
Only one thread should ever be in this function (no other locking is
done).

@raise SSHException: if the packet is mangled
@raise NeedRekeyException: if the transport should rekey