code: def parse_message(data, integrity_key=None):
      
      if len(data) < HEADER_LENGTH:
          raise ValueError('STUN message length is less than 20 bytes')
      message_type, length, cookie, transaction_id = unpack('!HHI12s', data[0:HEADER_LENGTH])
      if len(data) != HEADER_LENGTH + length:
          raise ValueError('STUN message length does not match')
  
      attributes = OrderedDict()
      pos = HEADER_LENGTH
      while pos <= len(data) - 4:
          attr_type, attr_len = unpack('!HH', data[pos:pos + 4])
          v = data[pos + 4:pos + 4 + attr_len]
          pad_len = 4 * ((attr_len + 3) // 4) - attr_len
          if attr_type in ATTRIBUTES_BY_TYPE:
              _, attr_name, attr_pack, attr_unpack = ATTRIBUTES_BY_TYPE[attr_type]
              if attr_unpack == unpack_xor_address:
                  attributes[attr_name] = attr_unpack(v, transaction_id=transaction_id)
              else:
                  attributes[attr_name] = attr_unpack(v)
  
              if attr_name == 'FINGERPRINT':
                  if attributes[attr_name] != message_fingerprint(data[0:pos]):
                      raise ValueError('STUN message fingerprint does not match')
              elif attr_name == 'MESSAGE-INTEGRITY':
                  if (integrity_key is not None and
                     attributes[attr_name] != message_integrity(data[0:pos], integrity_key)):
                      raise ValueError('STUN message integrity does not match')
  
          pos += 4 + attr_len + pad_len
      return Message(
          message_method=message_type & 0x3eef,
          message_class=message_type & 0x0110,
          transaction_id=transaction_id,
          attributes=attributes)
docs: Parses a STUN message.
  
      If the ``integrity_key`` parameter is given, the message's HMAC will be verified.