Esempio n. 1
0
def _unpack_multipacket_header(payload_offset, packet):
    if payload_offset == 9:  # GoldSrc
        pkt_byte, = _unpack_from('<B', packet, 8)
        return pkt_byte >> 2, pkt_byte & 0xF, False  # idx, total, compressed
    elif payload_offset in (10, 12, 18):  # Source
        pkt_id, num_pkts, pkt_idx, = _unpack_from('<LBB', packet, 4)
        return pkt_idx, num_pkts, (pkt_id & 0x80000000) != 0   # idx, total, compressed
    else:
        raise RuntimeError("Unexpected payload_offset - %d" % payload_offset)
Esempio n. 2
0
def _unpack_multipacket_header(payload_offset, packet):
    if payload_offset == 9:  # GoldSrc
        pkt_byte, = _unpack_from('<B', packet, 8)
        return pkt_byte >> 2, pkt_byte & 0xF, False  # idx, total, compressed
    elif payload_offset in (10, 12, 18):  # Source
        pkt_id, num_pkts, pkt_idx, = _unpack_from('<LBB', packet, 4)
        return pkt_idx, num_pkts, (pkt_id & 0x80000000) != 0   # idx, total, compressed
    else:
        raise RuntimeError("Unexpected payload_offset - %d" % payload_offset)
Esempio n. 3
0
 def random(self):
     """Get the next random number in the range [0.0, 1.0)."""
     value = _unpack_from('Q', self._cache, self._pos)[0] * FLOAT_CONV_CONSTANT
     self._pos += 8
     if self._pos >= self._cache_size:
         self.refresh()
     return value
Esempio n. 4
0
 def load_record_from_buffer(self, memview, start):
     start = super(_BsaHashedRecord, self).load_record_from_buffer(memview,
                                                                   start)
     for f, a in izip(self.__class__.formats, self.__class__.__slots__):
         setattr(self, a, _unpack_from(f[0], memview, start)[0])
         start += f[1]
     return start
Esempio n. 5
0
def a2s_rules(server_addr, timeout=2, challenge=0, binary=False):
    """Get rules from server

    :param server_addr: (ip, port) for the server
    :type  server_addr: tuple
    :param timeout: (optional) timeout in seconds
    :type  timeout: float
    :param challenge: (optional) challenge number
    :type  challenge: int
    :param binary: (optional) return rules as raw bytes
    :type  binary: bool
    :raises: :class:`RuntimeError`, :class:`socket.timeout`
    :returns: a list of rules
    :rtype: :class:`dict`
    """
    ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    ss.connect(server_addr)
    ss.settimeout(timeout)

    # request challenge number
    if challenge in (-1, 0):
        ss.send(_pack('<lci', -1, b'V', challenge))
        try:
            _, header, challenge = _unpack_from('<lcl', ss.recv(512))
        except:
            ss.close()
            raise

        if header != b'A':
            raise RuntimeError("Unexpected challenge response")

    # request player info
    ss.send(_pack('<lci', -1, b'V', challenge))

    try:
        data = StructReader(_handle_a2s_response(ss))
    finally:
        ss.close()

    header, num_rules = data.unpack('<4xcH')

    if header != b'E':
        raise RuntimeError("Invalid response header - %s" % repr(header))

    rules = {}

    while len(rules) != num_rules:
        name = data.read_cstring(binary=binary)
        value = data.read_cstring(binary=binary)

        if not binary:
            if _re_match(r'^\-?[0-9]+$', value):
                value = int(value)
            elif _re_match(r'^\-?[0-9]+\.[0-9]+$', value):
                value = float(value)

        rules[name] = value

    return rules
Esempio n. 6
0
def a2s_rules(server_addr, timeout=2, challenge=0):
    """Get rules from server

    :param server_addr: (ip, port) for the server
    :type  server_addr: tuple
    :param timeout: (optional) timeout in seconds
    :type  timeout: float
    :param challenge: (optional) challenge number
    :type  challenge: int
    :raises: :class:`RuntimeError`, :class:`socket.timeout`
    :returns: a list of players
    :rtype: :class:`list`
    """
    ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    ss.connect(server_addr)
    ss.settimeout(timeout)

    # request challenge number
    if challenge in (-1, 0):
        ss.send(_pack('<lci', -1, b'V', challenge))
        try:
            _, header, challenge = _unpack_from('<lcl', ss.recv(512))
        except:
            ss.close()
            raise

        if header != b'A':
            raise RuntimeError("Unexpected challenge response")

    # request player info
    ss.send(_pack('<lci', -1, b'V', challenge))

    try:
        data = StructReader(_handle_a2s_response(ss))
    finally:
        ss.close()

    header, num_rules = data.unpack('<4xcH')

    if header != b'E':
        raise RuntimeError("Invalid reponse header - %s" % repr(header))

    rules = {}

    while len(rules) != num_rules:
        name = data.read_cstring()
        value = data.read_cstring()

        if _re_match(r'^\-?[0-9]+$', value):
            value = int(value)
        elif _re_match(r'^\-?[0-9]+\.[0-9]+$', value):
            value = float(value)

        rules[name] = value

    return rules
Esempio n. 7
0
    def unpack(self, format_text):
        """Unpack bytes using struct modules format

        :param format_text: struct's module format
        :type  format_text: :class:`str`
        :return data: result from :func:`struct.unpack_from`
        :rtype: :class:`tuple`
        """
        data = _unpack_from(format_text, self.data, self.offset)
        self.offset += _calcsize(format_text)
        return data
Esempio n. 8
0
    def unpack(self, format_text):
        """Unpack bytes using struct modules format

        :param format_text: struct's module format
        :type  format_text: :class:`str`
        :return data: result from :func:`struct.unpack_from`
        :rtype: :class:`tuple`
        """
        data = _unpack_from(format_text, self.data, self.offset)
        self.offset += _calcsize(format_text)
        return data
def _handle_a2s_response(sock):
    packet = sock.recv(2048)
    header, = _unpack_from('<l', packet)

    if header == -1:  # single packet response
        return packet
    elif header == -2:  # multi packet response
        sock.settimeout(0.3)
        return _handle_a2s_multi_packet_response(sock, packet)
    else:
        raise RuntimeError("Invalid reponse header - %d" % header)
Esempio n. 10
0
def _handle_a2s_response(sock):
    packet = sock.recv(2048)
    header, = _unpack_from('<l', packet)

    if header == -1:  # single packet response
        return packet
    elif header == -2:  # multi packet response
        sock.settimeout(0.3)
        return _handle_a2s_multi_packet_response(sock, packet)
    else:
        raise RuntimeError("Invalid reponse header - %d" % header)
def _handle_a2s_multi_packet_response(sock, packet):
    packets, payload_offset = [packet], -1

    # locate first packet and handle out of order packets
    while payload_offset == -1:
        # locate payload offset in uncompressed packet
        payload_offset = packet.find(b'\xff\xff\xff\xff', 0, 18)

        # locate payload offset in compressed packet
        if payload_offset == -1:
            payload_offset = packet.find(b'BZh', 0, 21)

        # if we still haven't found the offset receive the next packet
        if payload_offset == -1:
            packet = sock.recv(2048)
            packets.append(packet)

    # read header
    pkt_idx, num_pkts, compressed = _unpack_multipacket_header(
        payload_offset, packet)

    if pkt_idx != 0:
        raise RuntimeError("Unexpected first packet index")

    # recv any remaining packets
    while len(packets) < num_pkts:
        packets.append(sock.recv(2048))

    # ensure packets are in correct order
    packets = sorted(map(
        lambda pkt: (_unpack_multipacket_header(payload_offset, pkt)[0], pkt),
        packets,
    ),
                     key=lambda x: x[0])

    # reconstruct full response
    data = b''.join(map(lambda x: x[1][payload_offset:], packets))

    # decompress response if needed
    if compressed:
        size, checksum = _unpack_from('<ll', packet, 10)
        data = _bz2_decompress(data)

        if len(data) != size:
            raise RuntimeError("Response size mismatch - %d %d" %
                               (len(data), size))
        if checksum != crc32(data):
            raise RuntimeError("Response checksum mismatch - %d %d" %
                               (checksum, crc32(data)))

    return data
Esempio n. 12
0
def _handle_a2s_multi_packet_response(sock, packet):
    packets, payload_offset = [packet], -1

    # locate first packet and handle out of order packets
    while payload_offset == -1:
        # locate payload offset in uncompressed packet
        payload_offset = packet.find(b'\xff\xff\xff\xff', 0, 18)

        # locate payload offset in compressed packet
        if payload_offset == -1:
            payload_offset = packet.find(b'BZh', 0, 21)

        # if we still haven't found the offset receive the next packet
        if payload_offset == -1:
            packet = sock.recv(2048)
            packets.append(packet)

    # read header
    pkt_idx, num_pkts, compressed = _unpack_multipacket_header(payload_offset, packet)

    if pkt_idx != 0:
        raise RuntimeError("Unexpected first packet index")

    # recv any remaining packets
    while len(packets) < num_pkts:
        packets.append(sock.recv(2048))

    # ensure packets are in correct order
    packets = sorted(map(lambda pkt: (_unpack_multipacket_header(payload_offset, pkt)[0], pkt),
                         packets,
                         ),
                     key=lambda x: x[0])

    # reconstruct full response
    data = b''.join(map(lambda x: x[1][payload_offset:], packets))

    # decompress response if needed
    if compressed:
        size, checksum = _unpack_from('<ll', packet, 10)
        data = _bz2_decompress(data)

        if len(data) != size:
            raise RuntimeError("Response size mismatch - %d %d" % (len(data), size))
        if checksum != crc32(data):
            raise RuntimeError("Response checksum mismatch - %d %d" % (checksum, crc32(data)))

    return data
Esempio n. 13
0
 def _load_bsa_light(self):
     my_header = self.bsa_header # type: Ba2Header
     with open(u'%s' % self.abs_path, u'rb') as bsa_file:
         # load the header from input stream
         my_header.load_header(bsa_file, self.bsa_name)
         # load the file names block
         bsa_file.seek(my_header.ba2_name_table_offset)
         file_names_block = memoryview(bsa_file.read())
         # close the file
     _filenames = []
     for index in xrange(my_header.ba2_num_files):
         name_size = _unpack_from(u'H', file_names_block)[0]
         filename = _decode_path(
             file_names_block[2:name_size + 2].tobytes(), self.bsa_name)
         _filenames.append(filename)
         file_names_block = file_names_block[name_size + 2:]
     self._filenames = _filenames
Esempio n. 14
0
 def _load_bsa(self):
     with open(u'%s' % self.abs_path, u'rb') as bsa_file:
         # load the header from input stream
         my_header = self.bsa_header # type: Ba2Header
         my_header.load_header(bsa_file, self.bsa_name)
         # load the folder records from input stream
         if my_header.ba2_files_type == b'GNRL':
             file_record_type = Ba2FileRecordGeneral
         else:
             file_record_type = Ba2FileRecordTexture
         file_records = []
         for __ in xrange(my_header.ba2_num_files):
             rec = file_record_type()
             rec.load_record(bsa_file)
             file_records.append(rec)
         # load the file names block
         bsa_file.seek(my_header.ba2_name_table_offset)
         file_names_block = memoryview(bsa_file.read())
         # close the file
     current_folder_name = current_folder = None
     for index in xrange(my_header.ba2_num_files):
         name_size = _unpack_from(u'H', file_names_block)[0]
         filename = _decode_path(
             file_names_block[2:name_size + 2].tobytes(), self.bsa_name)
         file_names_block = file_names_block[name_size + 2:]
         folder_dex = filename.rfind(u'\\')
         if folder_dex == -1:
             folder_name = u''
         else:
             folder_name = filename[:folder_dex]
         if current_folder_name != folder_name:
             current_folder = self.bsa_folders.setdefault(folder_name,
                                                          Ba2Folder())
             current_folder_name = folder_name
         current_folder.folder_assets[filename[folder_dex + 1:]] = \
             file_records[index]
Esempio n. 15
0
def unpack_int64(packed_bytes: bytes, offset = 0): return _unpack_from("=q", packed_bytes, offset)[0]
def unpack_float(packed_bytes: bytes, offset = 0): return _unpack_from("=f", packed_bytes, offset)[0]
Esempio n. 16
0
 def load_record_from_buffer(self, memview, start):
     f, f_size = _HashedRecord.formats[0]
     self.record_hash, = _unpack_from(f, memview, start)
     return start + f_size
Esempio n. 17
0
def unpack_uint16_le(packed_bytes: bytes, offset = 0): return _unpack_from("<H", packed_bytes, offset)[0]
def unpack_uint32_le(packed_bytes: bytes, offset = 0): return _unpack_from("<I", packed_bytes, offset)[0]
Esempio n. 18
0
def unpack_int16_be(packed_bytes: bytes, offset = 0): return _unpack_from(">h", packed_bytes, offset)[0]
def unpack_int32_be(packed_bytes: bytes, offset = 0): return _unpack_from(">i", packed_bytes, offset)[0]
Esempio n. 19
0
def unpack_uint64(packed_bytes: bytes, offset = 0): return _unpack_from("=Q", packed_bytes, offset)[0]
def unpack_int8(packed_bytes: bytes, offset = 0): return _unpack_from("=b", packed_bytes, offset)[0]
Esempio n. 20
0
 def unpack_from(fmt, view, _unpack_from=_unpack_from):  # noqa
     return _unpack_from(fmt, view.tobytes())  # <- memoryview
Esempio n. 21
0
def unpack_float_le(packed_bytes: bytes, offset = 0): return _unpack_from("<f", packed_bytes, offset)[0]
def unpack_double_le(packed_bytes: bytes, offset = 0): return _unpack_from("<d", packed_bytes, offset)[0]
Esempio n. 22
0
def a2s_players(server_addr, timeout=2, challenge=0):
    """Get list of players and their info

    :param server_addr: (ip, port) for the server
    :type  server_addr: tuple
    :param timeout: (optional) timeout in seconds
    :type  timeout: float
    :param challenge: (optional) challenge number
    :type  challenge: int
    :raises: :class:`RuntimeError`, :class:`socket.timeout`
    :returns: a list of players
    :rtype: :class:`list`
    """
    ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    ss.connect(server_addr)
    ss.settimeout(timeout)

    # request challenge number
    header = None

    if challenge in (-1, 0):
        ss.send(_pack('<lci', -1, b'U', challenge))
        try:
            data = ss.recv(512)
            _, header, challenge = _unpack_from('<lcl', data)
        except:
            ss.close()
            raise

        if header not in b'AD':  # work around for CSGO sending only max players
            raise RuntimeError("Unexpected challenge response - %s" % repr(header))

    # request player info
    if header == b'D':  # work around for CSGO sending only max players
        data = StructReader(data)
    else:
        ss.send(_pack('<lci', -1, b'U', challenge))

        try:
            data = StructReader(_handle_a2s_response(ss))
        finally:
            ss.close()

    header, num_players = data.unpack('<4xcB')

    if header != b'D':
        raise RuntimeError("Invalid reponse header - %s" % repr(header))

    players = []

    while len(players) < num_players:
        player = dict()
        player['index'] = data.unpack('<B')[0]
        player['name'] = data.read_cstring()
        player['score'], player['duration'] = data.unpack('<lf')
        players.append(player)

    if data.rlen() / 8 == num_players:  # assume the ship server
        for player in players:
            player['deaths'], player['money'] = data.unpack('<ll')

    return players
Esempio n. 23
0
def unpack_double_le(packed_bytes: bytes, offset = 0): return _unpack_from("<d", packed_bytes, offset)[0]

def unpack_uint8_be(packed_bytes: bytes, offset = 0): return _unpack_from(">B", packed_bytes, offset)[0]
Esempio n. 24
0
def unpack_uint16(packed_bytes: bytes, offset = 0): return _unpack_from("=H", packed_bytes, offset)[0]
def unpack_uint32(packed_bytes: bytes, offset = 0): return _unpack_from("=I", packed_bytes, offset)[0]
Esempio n. 25
0
def unpack_uint16_be(packed_bytes: bytes, offset = 0): return _unpack_from(">H", packed_bytes, offset)[0]
def unpack_uint32_be(packed_bytes: bytes, offset = 0): return _unpack_from(">I", packed_bytes, offset)[0]
Esempio n. 26
0
def unpack_float_be(packed_bytes: bytes, offset = 0): return _unpack_from(">f", packed_bytes, offset)[0]
def unpack_double_be(packed_bytes: bytes, offset = 0): return _unpack_from(">d", packed_bytes, offset)[0]
Esempio n. 27
0
def unpack_int64_be(packed_bytes: bytes, offset = 0): return _unpack_from(">q", packed_bytes, offset)[0]
def unpack_float_be(packed_bytes: bytes, offset = 0): return _unpack_from(">f", packed_bytes, offset)[0]
Esempio n. 28
0
def unpack_int64_le(packed_bytes: bytes, offset = 0): return _unpack_from("<q", packed_bytes, offset)[0]
def unpack_float_le(packed_bytes: bytes, offset = 0): return _unpack_from("<f", packed_bytes, offset)[0]
Esempio n. 29
0
 def unpack_from(fmt, view, _unpack_from=_unpack_from):  # noqa
     return _unpack_from(fmt, view.tobytes())  # <- memoryview
Esempio n. 30
0
def unpack_int16_le(packed_bytes: bytes, offset = 0): return _unpack_from("<h", packed_bytes, offset)[0]
def unpack_int32_le(packed_bytes: bytes, offset = 0): return _unpack_from("<i", packed_bytes, offset)[0]
Esempio n. 31
0
def unpack_int16(packed_bytes: bytes, offset = 0): return _unpack_from("=h", packed_bytes, offset)[0]
def unpack_int32(packed_bytes: bytes, offset = 0): return _unpack_from("=i", packed_bytes, offset)[0]
Esempio n. 32
0
def unpack_uint64_le(packed_bytes: bytes, offset = 0): return _unpack_from("<Q", packed_bytes, offset)[0]
def unpack_int8_le(packed_bytes: bytes, offset = 0): return _unpack_from("<b", packed_bytes, offset)[0]
def a2s_players(server_addr, timeout=2, challenge=0):
    """Get list of players and their info

    :param server_addr: (ip, port) for the server
    :type  server_addr: tuple
    :param timeout: (optional) timeout in seconds
    :type  timeout: float
    :param challenge: (optional) challenge number
    :type  challenge: int
    :raises: :class:`RuntimeError`, :class:`socket.timeout`
    :returns: a list of players
    :rtype: :class:`list`
    """
    ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    ss.connect(server_addr)
    ss.settimeout(timeout)

    # request challenge number
    header = None

    if challenge in (-1, 0):
        ss.send(_pack('<lci', -1, b'U', challenge))
        try:
            data = ss.recv(512)
            _, header, challenge = _unpack_from('<lcl', data)
        except:
            ss.close()
            raise

        if header not in b'AD':  # work around for CSGO sending only max players
            raise RuntimeError("Unexpected challenge response - %s" %
                               repr(header))

    # request player info
    if header == b'D':  # work around for CSGO sending only max players
        data = StructReader(data)
    else:
        ss.send(_pack('<lci', -1, b'U', challenge))

        try:
            data = StructReader(_handle_a2s_response(ss))
        finally:
            ss.close()

    header, num_players = data.unpack('<4xcB')

    if header != b'D':
        raise RuntimeError("Invalid reponse header - %s" % repr(header))

    players = []

    while len(players) < num_players:
        player = dict()
        player['index'] = data.unpack('<B')[0]
        player['name'] = data.read_cstring()
        player['score'], player['duration'] = data.unpack('<lf')
        players.append(player)

    if data.rlen() / 8 == num_players:  # assume the ship server
        for player in players:
            player['deaths'], player['money'] = data.unpack('<ll')

    return players
Esempio n. 34
0
def unpack_uint64_be(packed_bytes: bytes, offset = 0): return _unpack_from(">Q", packed_bytes, offset)[0]
def unpack_int8_be(packed_bytes: bytes, offset = 0): return _unpack_from(">b", packed_bytes, offset)[0]