def _EOSEventRecord(self): '''Return desired endianness for a single EOS Event Record''' return Struct( 'Bytes' / self._UInt32, Embedded( Struct( 'EventCode' / self._EOSEventCode, 'Record' / Switch( lambda ctx: ctx.EventCode, { 'DevicePropChanged': Embedded( Struct( 'PropertyCode' / self._EOSPropertyCode, 'Enumeration' / Array( lambda ctx: ctx._._.Bytes / 4 - 3, # TODO: Automatically decode each property # code's enumeration values. self._UInt32), )), 'AvailListChanged': Embedded( Struct( 'PropertyCode' / self._EOSPropertyCode, 'Enumeration' / Array( # TODO: Verify if this is actually an # enumeration. lambda ctx: ctx._._.Bytes / 4 - 3, self._UInt32))), }, default=Array(lambda ctx: ctx._.Bytes / 4 - 2, self._UInt32)))))
def test_overwrite(self): s = Struct("s", Byte("a"), Byte("a"), allow_overwrite = True ) self.assertEqual(s.parse(b"\x01\x02").a, 2) s = Struct("s", Byte("a"), Embedded(Struct("b", Byte("a"), allow_overwrite = True )), ) self.assertEqual(s.parse(b"\x01\x02").a, 2) s = Struct("s", Embedded(Struct("b", Byte("a"), )), Byte("a"), allow_overwrite = True ) self.assertEqual(s.parse(b"\x01\x02").a, 2)
def perf_event_header(): return Embedded(Struct(None, Enum(UNInt32("type"), MMAP = 1, LOST = 2, COMM = 3, EXIT = 4, THROTTLE = 5, UNTHROTTLE = 6, FORK = 7, READ = 8, SAMPLE = 9, MMAP2 = 10, RECORD_AUX = 11, ITRACE_START = 12, LOST_SAMPLES = 13, SWITCH = 14, SWITCH_CPU_WIDE = 15, NAMESPACES = 16, KSYMBOL = 17, BPF_EVENT = 18, CGROUP = 19, HEADER_ATTR = 64, HEADER_EVENT_TYPE = 65, TRACING_DATA = 66, HEADER_BUILD_ID = 67, FINISHED_ROUND = 68, ID_INDEX = 69, AUXTRACE_INFO = 70, AUXTRACE = 71, AUXTRACE_ERROR = 72, THREAD_MAP = 73, CPU_MAP = 74, STAT_CONFIG = 75, STAT = 76, STAT_ROUND = 77, EVENT_UPDATE = 78, TIME_CONV = 79, HEADER_FEATURE = 80, COMPRESSED = 81), Embedded(BitStruct(None, Padding(1), Enum(BitField("cpumode", 7), UNKNOWN = 0, KERNEL = 1, USER = 2, HYPERVISOR = 3, GUEST_KERNEL = 4, GUEST_USER = 5), Flag("ext_reserved"), Flag("exact_ip"), Flag("mmap_data"), Padding(5))), UNInt16("size"), If(has_sample_id_all, Pointer(lambda ctx: ctx.start + ctx.size - 8, UNInt64("end_id"))), Value("attr", lookup_event_attr)))
def read_format(): return Struct( "read", If( lambda ctx: read_flags(ctx).group, Struct( "group", UNInt64("nr"), Embedded(enabled_running()), Array( lambda ctx: ctx.nr, Struct("val", UNInt64("value"), If(lambda ctx: read_flags(ctx).id, UNInt64("id2")))))), If( lambda ctx: not read_flags(ctx).group, Struct("single", UNInt64("value"), Embedded(enabled_running()), If(lambda ctx: read_flags(ctx).id, UNInt64("id2")))))
def sample_id(): return If( lambda ctx: True, # xxx check size Embedded( Struct( "id_all", If(lambda ctx: sample_type(ctx).tid, Embedded(Struct("pid2", SNInt32("pid2"), SNInt32("tid2")))), If(lambda ctx: sample_type(ctx).time, UNInt64("time2")), If(lambda ctx: sample_type(ctx).id, UNInt64("id2")), If(lambda ctx: sample_type(ctx).stream_id, UNInt64("stream_id2")), If(lambda ctx: sample_type(ctx).cpu, Embedded(Struct("cpu", UNInt32("cpu2"), UNInt32("res")))), If(lambda ctx: sample_type(ctx).identifier, UNInt64("identifier2")))))
def _RangeForm(self, element): return Embedded( Sequence( 'MinimumValue' / element, 'MaximumValue' / element, 'StepSize' / element, ))
def getrequest(reqtype): payload = None if reqtype == "SetOnOff": payload = OnOff elif reqtype == "SetBrightness": payload = Brightness return "msg" / Padded( 18, Struct(Const(0x43, Int8ub), "type" / RequestType, "payload" / Embedded(payload)))
def test_no_overwrite(self): s = Struct( "s", Byte("a"), Byte("a"), ) self.assertRaises(OverwriteError, s.parse, six.b("\x01\x02")) s = Struct("s", Byte("a"), Embedded(Struct( "b", Byte("a"), )), allow_overwrite=True) self.assertRaises(OverwriteError, s.parse, six.b("\x01\x02")) s = Struct( "s", Embedded(Struct("b", Byte("a"), allow_overwrite=True)), Byte("a"), ) self.assertRaises(OverwriteError, s.parse, six.b("\x01\x02"))
def perf_event_header(): return Embedded( Struct( None, Enum(UNInt32("type"), MMAP=1, LOST=2, COMM=3, EXIT=4, THROTTLE=5, UNTHROTTLE=6, FORK=7, READ=8, SAMPLE=9, MMAP2=10, TRACING_DATA=66, FINISHED_ROUND=68, ID_INDEX=69, AUXTRACE_INFO=70, AUXTRACE=71, AUXTRACE_ERROR=72), Embedded( BitStruct( None, Padding(1), Enum(BitField("cpumode", 7), UNKNOWN=0, KERNEL=1, USER=2, HYPERVISOR=3, GUEST_KERNEL=4, GUEST_USER=5), Flag("ext_reserved"), Flag("exact_ip"), Flag("mmap_data"), Padding(5))), UNInt16("size"), If( has_sample_id_all, Pointer(lambda ctx: ctx.start + ctx.size - 8, UNInt64("end_id"))), Value("attr", lookup_event_attr)))
def mmap(): return Struct("mmap", SNInt32("pid"), SNInt32("tid"), UNInt64("addr"), UNInt64("len"), UNInt64("pgoff"), Anchor("start_of_filename"), CString("filename"), Anchor("end_of_filename"), # hack for now. this shouldn't be needed. If(lambda ctx: True, # XXX Embedded(Pointer(lambda ctx: ctx.size + ctx.start - sample_id_size(ctx), sample_id()))))
def perf_features(): return Struct("features", # XXX If(lambda ctx: ctx._.tracing_data, perf_file_section("tracing_data", Pass)), If(lambda ctx: ctx._.build_id, section_adapter("build_id", GreedyRange(build_id()))), feature_string("hostname"), feature_string("osrelease"), feature_string("version"), feature_string("arch"), If(lambda ctx: ctx._.nrcpus, perf_file_section("nrcpus", Embedded(Struct("nrcpus", UNInt32("nr_cpus_online"), UNInt32("nr_cpus_avail"))))), feature_string("cpudesc"), feature_string("cpuid"), If(lambda ctx: ctx._.total_mem, perf_file_section("total_mem", UNInt64("total_mem"))), If(lambda ctx: ctx._.cmdline, perf_file_section("cmdline", string_list("cmdline"))), If(lambda ctx: ctx._.event_desc, perf_file_section("event_desc", event_desc())), If(lambda ctx: ctx._.cpu_topology, perf_file_section("cpu_topology", Struct("cpu_topology", string_list("cores"), string_list("threads")))), If(lambda ctx: ctx._.numa_topology, perf_file_section("numa_topology", numa_topology())), # not implemented in perf If(lambda ctx: ctx._.branch_stack, perf_file_section("branch_stack", Pass)), If(lambda ctx: ctx._.pmu_mappings, perf_file_section("pmu_mappings", pmu_mappings())), If(lambda ctx: ctx._.group_desc, perf_file_section("group_desc", group_desc())))
def EmbeddedBitStruct(name, *args, reversed=False): """ Emulates BitStruct embedding: - for parsing, adds Computed accessor fields to the parent construct, - for building, Rebuild the bit struct using keys passed to the parent NOTE: This is a hack. Do not use unless you absolutely have to. """ bit_struct = BitStruct(*args) if reversed: bit_struct = Reversed(bit_struct) bit_struct.__construct_doc__ = Embedded(Struct(*args)) return (name / Rebuild(bit_struct, dict), ) + \ tuple(i.name / Computed(this[name][i.name]) for i in args if i.name is not None)
def perf_event(): return Struct( "perf_event", Anchor("start"), perf_event_header(), Anchor("header_end"), Switch( "data", lambda ctx: ctx.type, { "MMAP": mmap(), # noqa E121 "MMAP2": mmap2(), "LOST": Struct("lost", UNInt64("id"), UNInt64("lost"), sample_id()), "COMM": Struct("comm", SNInt32("pid"), SNInt32("tid"), CString("comm"), sample_id()), "EXIT": fork_exit("exit"), "THROTTLE": throttle("throttle"), "UNTHROTTLE": throttle("unthrottle"), "FINISHED_ROUND": Pass, "FORK": fork_exit("fork"), "READ": Embedded( Struct("read_event", SNInt32("pid"), SNInt32("tid"), read_format(), sample_id())), "SAMPLE": event() }), Anchor("end"), Padding(lambda ctx: ctx.size - (ctx.end - ctx.start)))
ConstructDockWeakness = Struct( index=VarInt, name=CString("utf8"), is_blast_door=Flag, requirement=ConstructRequirement, ) ConstructResourceDatabase = Struct( items=PrefixedArray(VarInt, ConstructItemResourceInfo), events=PrefixedArray(VarInt, ConstructResourceInfo), tricks=PrefixedArray(VarInt, ConstructTrickResourceInfo), damage=PrefixedArray( VarInt, Struct( Embedded(ConstructResourceInfo), reductions=PrefixedArray( VarInt, Struct( index=VarInt, multiplier=Float32b, )), )), versions=PrefixedArray(VarInt, ConstructResourceInfo), misc=PrefixedArray(VarInt, ConstructResourceInfo), requirement_template=PrefixedArray( VarInt, Sequence(CString("utf8"), ConstructRequirement))) ConstructEchoesBeamConfiguration = Struct( item_index=VarInt, ammo_a=OptionalValue(Byte), ammo_b=OptionalValue(Byte),
"panel_id" / Int16ub, "pc_password" / Default(Bytes(2), b'0000'), "modem_speed" / Bytes(1), "source_method" / Default( Enum(Int8ub, Winload_Connection=0x00, NEware_Connection=0x55), 0x00), "user_code" / Default(Int24ub, 0x000000), "serial_number" / Bytes(4), "system_options" / BitsSwapped( BitStruct( Embedded( Struct( # EVO section data 3030 "pgm1_smoke" / Flag, "no_bell_cut_off" / Flag, "daylight_saving_time" / Flag, "shabbat_feature" / Flag, "battery_charge_current" / Flag, "ac_failure_not_displayed_as_trouble" / Flag, "clear_bell_limit_trouble" / Flag, "combus_speed" / Flag, )), "partitions" / StatusFlags(8), # EVO section data 3031 "siren_output_partition" / StatusFlags(8), # EVO section data 3032 Embedded( Struct( # EVO section data 3033 "multiple_actions_user_menu" / Flag, "user_code_length_flexible" / Flag, "user_code_length_6" / Flag, "power_save_mode" / Flag, "bypass_not_displayed_when_armed" / Flag,
"""Entry point for reading MGZ.""" # pylint: disable=invalid-name,no-name-in-module from construct import (Struct, CString, Const, Int32ul, Embedded, Float32l, Terminated, If, this) from mgz.util import MgzPrefixed, ZlibCompressed from mgz.header.ai import ai from mgz.header.replay import replay from mgz.header.map_info import map_info from mgz.header.initial import initial from mgz.header.achievements import achievements from mgz.header.scenario import scenario from mgz.header.lobby import lobby from mgz.header.de import de compressed_header = Struct("version" / CString(encoding='latin1'), "sub_version" / Float32l, "de" / If(this.version == 'VER 9.4', de), ai, replay, map_info, initial, achievements, scenario, lobby, Terminated) subheader = Struct( "chapter_address" / Int32ul, Embedded( MgzPrefixed(this._.header_length - 8, ZlibCompressed(compressed_header)))) """Header is compressed""" header = Struct("header_length" / Int32ul, Embedded(subheader))
def __setup_constructors(self): '''Set endianness and create transport-specific constructors.''' # Set endianness of constructors before using them. self._set_endian('little') self.__Length = Int32ul self.__Type = Enum( Int16ul, default=Pass, Undefined=0x0000, Command=0x0001, Data=0x0002, Response=0x0003, Event=0x0004, ) # This is just a convenience constructor to get the size of a header. self.__Code = Int16ul self.__Header = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'Code' / self.__Code, 'TransactionID' / self._TransactionID, ) # These are the actual constructors for parsing and building. self.__CommandHeader = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'OperationCode' / self._OperationCode, 'TransactionID' / self._TransactionID, ) self.__ResponseHeader = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'ResponseCode' / self._ResponseCode, 'TransactionID' / self._TransactionID, ) self.__EventHeader = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'EventCode' / self._EventCode, 'TransactionID' / self._TransactionID, ) # Apparently nobody uses the SessionID field. Even though it is # specified in ISO15740:2013(E), no device respects it and the session # number is implicit over USB. self.__Param = Range(0, 5, self._Parameter) self.__CommandTransactionBase = Struct( Embedded(self.__CommandHeader), 'Payload' / Bytes(lambda ctx, h=self.__Header: ctx.Length - h.sizeof())) self.__CommandTransaction = ExprAdapter( self.__CommandTransactionBase, encoder=lambda obj, ctx, h=self.__Header: Container( Length=len(obj.Payload) + h.sizeof(), **obj), decoder=lambda obj, ctx: obj, ) self.__ResponseTransactionBase = Struct( Embedded(self.__ResponseHeader), 'Payload' / Bytes(lambda ctx, h=self.__Header: ctx.Length - h.sizeof())) self.__ResponseTransaction = ExprAdapter( self.__ResponseTransactionBase, encoder=lambda obj, ctx, h=self.__Header: Container( Length=len(obj.Payload) + h.sizeof(), **obj), decoder=lambda obj, ctx: obj, )
from construct import Embedded, Struct from .common import record_layer, handshake_protocol server_hello_done_format = Struct( Embedded(record_layer), "handshake_protocol" / Struct( Embedded(handshake_protocol), ), )
from construct import Struct, Byte, Int16ub, Int64ub, Enum, Bytes, \ Int24ub, this, GreedyBytes, GreedyRange, Terminated, Embedded MerkleTreeHeader = Struct( "Version" / Byte, "MerkleLeafType" / Byte, "Timestamp" / Int64ub, "LogEntryType" / Enum(Int16ub, X509LogEntryType=0, PrecertLogEntryType=1), "Entry" / GreedyBytes) Certificate = Struct("Length" / Int24ub, "CertData" / Bytes(this.Length)) CertificateChain = Struct( "ChainLength" / Int24ub, "Chain" / GreedyRange(Certificate), ) PreCertEntry = Struct("LeafCert" / Certificate, Embedded(CertificateChain), Terminated) def dump_extensions(certificate): extensions = {} for x in range(certificate.get_extension_count()): extension_name = "" try: extension_name = certificate.get_extension(x).get_short_name() if extension_name == b'UNDEF': continue extensions[extension_name.decode( 'latin-1')] = certificate.get_extension(x).__str__()
# toggles the default stance when units are created. All players start on aggressive by default, if the player # (initially) has defensive enabled it is called right before the first unit is queued, and again every time # the player toggles it in the game options menu "default_stance" / If(this.mode == 'default_stance', Struct(Padding(9))), Padding(3)) droprelic = "droprelic" / Struct(Const(b"\x00\x00\x00"), 'unit_id' / Int32ul) wall = "wall" / Struct( "selected" / Byte, "player_id" / Byte, "start_x" / Byte, "start_y" / Byte, "end_x" / Byte, "end_y" / Byte, Padding(1), IfThenElse( lambda ctx: ctx._._.length - 16 - (ctx.selected * 4) == 8, Embedded( Struct("unk" / Bytes(4), "building_id" / Int32ul, Padding(4), "flags" / Bytes(4))), Embedded(Struct( "building_id" / Int32ul, Padding(4), ))), Array(lambda ctx: ctx.selected, "unit_ids" / Int32ul)) delete = "delete" / Struct(Padding(3), "object_id" / Int32ul, "player_id" / Int32ul) attackground = "attackground" / Struct( "selected" / Byte, Padding(2), "x" / Float32l, "y" / Float32l, "next" / Peek(Bytes(4)), "flags" / If(lambda ctx: check_flags(ctx.next), Bytes(4)), Array(lambda ctx: ctx.selected, "unit_ids" / Int32ul)) tribute = "tribute" / Struct("player_id" / Byte, "player_id_to" / Byte,
linked_building = "link" / Struct("unit_id" / Int16ul, "x_offset" / Float32l, "y_offset" / Float32l) building = "building" / Struct( combat, "construction_sprite" / Int16ul, "snow_sprite" / If(lambda ctx: find_version(ctx) != Version.AOK, Int16ul), "connect_flag" / Byte, "facet" / Int16ul, "destroy_on_build" / Byte, "on_build_make_unit" / Int16ul, "on_build_make_tile" / Int16ul, "on_build_make_overlay" / Int16ul, "on_build_make_tech" / Int16ul, "can_burn" / Byte, "linked_buildings" / Array(4, linked_building), "construction_unit" / Int16ul, "transform_unit" / Int16ul, "transform_sound" / Int16ul, "construction_sound" / Int16ul, "garrison_type" / Byte, "garrison_heal_rate" / Float32l, "garrison_repair_rate" / Float32l, "salvage_unit" / Int16ul, "salvage_attributes" / Array(6, Byte)) unit_type = "unit_type" / Struct( "type" / Byte, Embedded("properties" / Switch( this.type, { 10: base, 15: base, 20: animated, 25: animated, 30: moving, 40: action, 50: base_combat, 60: missile, 70: combat, 80: building })))
class IPTransport(object): '''Implement IP transport.''' def __init__(self, device=None): '''Instantiate the first available PTP device over IP''' self.__setup_constructors() logger.debug('Init IP') self.__dev = device if device is None: raise NotImplementedError( 'IP discovery not implemented. Please provide a device.' ) self.__device = device # Signal usable implicit session self.__implicit_session_open = Event() # Signal implicit session is shutting down self.__implicit_session_shutdown = Event() self.__check_session_lock = Lock() self.__transaction_lock = Lock() self.__event_queue = Queue() atexit.register(self._shutdown) def _shutdown(self): try: self.__close_implicit_session() except Exception as e: logger.error(e) @contextmanager def __implicit_session(self): '''Manage implicit sessions with responder''' # There is now an implicit session self.__check_session_lock.acquire() if not self.__implicit_session_open.is_set(): try: self.__open_implicit_session() self.__check_session_lock.release() yield except Exception as e: logger.error(e) raise PTPError('Failed to open PTP/IP implicit session') finally: if self.__implicit_session_open.is_set(): self.__close_implicit_session() if self.__check_session_lock.locked(): self.__check_session_lock.release() else: self.__check_session_lock.release() yield def __open_implicit_session(self): '''Establish implicit session with responder''' self.__implicit_session_shutdown.clear() # Establish Command and Event connections if type(self.__device) is tuple: host, port = self.__device self.__setup_connection(host, port) else: self.__setup_connection(self.__device) self.__implicit_session_open.set() # Prepare Event and Probe threads self.__event_proc = Thread( name='EvtPolling', target=self.__poll_events ) self.__event_proc.daemon = False self.__ping_pong_proc = Thread( name='PingPong', target=self.__ping_pong ) self.__ping_pong_proc.daemon = False # Launch Event and Probe threads self.__event_proc.start() self.__ping_pong_proc.start() def __close_implicit_session(self): '''Terminate implicit session with responder''' self.__implicit_session_shutdown.set() if not self.__implicit_session_open.is_set(): return # Only join running threads. if self.__event_proc.is_alive(): self.__event_proc.join(2) if self.__ping_pong_proc.is_alive(): self.__ping_pong_proc.join(2) logger.debug('Close connections for {}'.format(repr(self.__dev))) try: self.__evtcon.shutdown(socket.SHUT_RDWR) except socket.error as e: if e.errno == 107: pass else: raise e try: self.__cmdcon.shutdown(socket.SHUT_RDWR) except socket.error as e: if e.errno == 107: pass else: raise e self.__evtcon.close() self.__cmdcon.close() self.__implicit_session_open.clear() def __setup_connection(self, host=None, port=15740): '''Establish a PTP/IP session for a given host''' logger.debug( 'Establishing PTP/IP connection with {}:{}' .format(host, port) ) socket.setdefaulttimeout(5) hdrlen = self.__Header.sizeof() # Command Connection Establishment self.__cmdcon = create_connection((host, port)) # Send InitCommand # TODO: Allow users to identify as an arbitrary initiator. init_cmd_req_payload = self.__InitCommand.build( Container( InitiatorGUID=16*[0xFF], InitiatorFriendlyName='PTPy', InitiatorProtocolVersion=Container( Major=100, Minor=000, ), )) init_cmd_req = self.__Packet.build( Container( Type='InitCommand', Payload=init_cmd_req_payload, ) ) actual_socket(self.__cmdcon).sendall(init_cmd_req) # Get ACK/NACK init_cmd_req_rsp = actual_socket(self.__cmdcon).recv(72) init_cmd_rsp_hdr = self.__Header.parse( init_cmd_req_rsp[0:hdrlen] ) if init_cmd_rsp_hdr.Type == 'InitCommandAck': cmd_ack = self.__InitCommandACK.parse(init_cmd_req_rsp[hdrlen:]) logger.debug( 'Command connection ({}) established' .format(cmd_ack.ConnectionNumber) ) elif init_cmd_rsp_hdr.Type == 'InitFail': cmd_nack = self.__InitFail.parse(init_cmd_req_rsp[hdrlen:]) msg = 'InitCommand failed, Reason: {}'.format( cmd_nack ) logger.error(msg) raise PTPError(msg) else: msg = 'Unexpected response Type to InitCommand : {}'.format( init_cmd_rsp_hdr.Type ) logger.error(msg) raise PTPError(msg) # Event Connection Establishment self.__evtcon = create_connection((host, port)) self.__evtcon.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.__evtcon.setsockopt(socket.IPPROTO_TCP, socket.SO_KEEPALIVE, 1) # Send InitEvent payload = self.__InitEvent.build(Container( ConnectionNumber=cmd_ack.ConnectionNumber, )) evt_req = self.__Packet.build( Container( Type='InitEvent', Payload=payload, ) ) actual_socket(self.__evtcon).sendall(evt_req) # Get ACK/NACK init_evt_req_rsp = actual_socket(self.__evtcon).recv( hdrlen + self.__InitFail.sizeof() ) init_evt_rsp_hdr = self.__Header.parse( init_evt_req_rsp[0:hdrlen] ) if init_evt_rsp_hdr.Type == 'InitEventAck': logger.debug( 'Event connection ({}) established' .format(cmd_ack.ConnectionNumber) ) elif init_evt_rsp_hdr.Type == 'InitFail': evt_nack = self.__InitFail.parse(init_evt_req_rsp[hdrlen:]) msg = 'InitEvent failed, Reason: {}'.format( evt_nack ) logger.error(msg) raise PTPError(msg) else: msg = 'Unexpected response Type to InitEvent : {}'.format( init_evt_rsp_hdr.Type ) logger.error(msg) raise PTPError(msg) # Helper methods. # --------------------- def __setup_constructors(self): '''Set endianness and create transport-specific constructors.''' # Set endianness of constructors before using them. self._set_endian('little') self.__Length = Int32ul self.__Type = Enum( Int32ul, Undefined=0x00000000, InitCommand=0x00000001, InitCommandAck=0x00000002, InitEvent=0x00000003, InitEventAck=0x00000004, InitFail=0x00000005, Command=0x00000006, Response=0x00000007, Event=0x00000008, StartData=0x00000009, Data=0x0000000A, Cancel=0x0000000B, EndData=0x0000000C, Ping=0x0000000D, Pong=0x0000000E, ) self.__Header = Struct( 'Length' / self.__Length, 'Type' / self.__Type, ) self.__Param = Range(0, 5, self._Parameter) self.__EventParam = Range(0, 3, self._Parameter) self.__PacketBase = Struct( Embedded(self.__Header), 'Payload' / Bytes( lambda ctx, h=self.__Header: ctx.Length - h.sizeof()), ) self.__Packet = ExprAdapter( self.__PacketBase, encoder=lambda obj, ctx, h=self.__Header: Container( Length=len(obj.Payload) + h.sizeof(), **obj ), decoder=lambda obj, ctx: obj, ) # Yet another arbitrary string type. Max-length CString utf8-encoded self.__PTPIPString = ExprAdapter( RepeatUntil( lambda obj, ctx, lst: six.unichr(obj) in '\x00' or len(lst) == 40, Int16ul ), encoder=lambda obj, ctx: [] if len(obj) == 0 else[ord(c) for c in six.text_type(obj)]+[0], decoder=lambda obj, ctx: u''.join( [six.unichr(o) for o in obj] ).split('\x00')[0], ) # PTP/IP packets # Command self.__ProtocolVersion = Struct( 'Major' / Int16ul, 'Minor' / Int16ul, ) self.__InitCommand = Embedded(Struct( 'InitiatorGUID' / Array(16, Int8ul), 'InitiatorFriendlyName' / self.__PTPIPString, 'InitiatorProtocolVersion' / self.__ProtocolVersion, )) self.__InitCommandACK = Embedded(Struct( 'ConnectionNumber' / Int32ul, 'ResponderGUID' / Array(16, Int8ul), 'ResponderFriendlyName' / self.__PTPIPString, 'ResponderProtocolVersion' / self.__ProtocolVersion, )) # Event self.__InitEvent = Embedded(Struct( 'ConnectionNumber' / Int32ul, )) # Common to Events and Command requests self.__Reason = Enum( # TODO: Verify these codes... Int32ul, Undefined=0x0000, RejectedInitiator=0x0001, Busy=0x0002, Unspecified=0x0003, ) self.__InitFail = Embedded(Struct( 'Reason' / self.__Reason, )) self.__DataphaseInfo = Enum( Int32ul, Undefined=0x00000000, In=0x00000001, Out=0x00000002, ) self.__Command = Embedded(Struct( 'DataphaseInfo' / self.__DataphaseInfo, 'OperationCode' / self._OperationCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__Param, )) self.__Response = Embedded(Struct( 'ResponseCode' / self._ResponseCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__Param, )) self.__Event = Embedded(Struct( 'EventCode' / self._EventCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__EventParam, )) self.__StartData = Embedded(Struct( 'TransactionID' / self._TransactionID, 'TotalDataLength' / Int64ul, )) # TODO: Fix packing and unpacking dataphase data self.__Data = Embedded(Struct( 'TransactionID' / self._TransactionID, 'Data' / Bytes( lambda ctx: ctx._.Length - self.__Header.sizeof() - self._TransactionID.sizeof() ), )) self.__EndData = Embedded(Struct( 'TransactionID' / self._TransactionID, 'Data' / Bytes( lambda ctx: ctx._.Length - self.__Header.sizeof() - self._TransactionID.sizeof() ), )) self.__Cancel = Embedded(Struct( 'TransactionID' / self._TransactionID, )) # Convenience construct for parsing packets self.__PacketPayload = Debugger(Struct( 'Header' / Embedded(self.__Header), 'Payload' / Embedded(Switch( lambda ctx: ctx.Type, { 'InitCommand': self.__InitCommand, 'InitCommandAck': self.__InitCommandACK, 'InitEvent': self.__InitEvent, 'InitFail': self.__InitFail, 'Command': self.__Command, 'Response': self.__Response, 'Event': self.__Event, 'StartData': self.__StartData, 'Data': self.__Data, 'EndData': self.__EndData, }, default=Pass, )) )) def __parse_response(self, ipdata): '''Helper method for parsing data.''' # Build up container with all PTP info. response = self.__PacketPayload.parse(ipdata) # Sneak in an implicit Session ID response['SessionID'] = self.session_id return response def __recv(self, event=False, wait=False, raw=False): '''Helper method for receiving packets.''' hdrlen = self.__Header.sizeof() with self.__implicit_session(): ip = ( actual_socket(self.__evtcon) if event else actual_socket(self.__cmdcon) ) data = bytes() while True: try: ipdata = ip.recv(hdrlen) except socket.timeout: if event: return None else: ipdata = ip.recv(hdrlen) if len(ipdata) == 0 and not event: raise PTPError('Command connection dropped') elif event: return None # Read a single entire header while len(ipdata) < hdrlen: ipdata += ip.recv(hdrlen - len(ipdata)) header = self.__Header.parse( ipdata[0:hdrlen] ) # Read a single entire packet while len(ipdata) < header.Length: ipdata += ip.recv(header.Length - len(ipdata)) # Run sanity checks. if header.Type not in [ 'Cancel', 'Data', 'Event', 'Response', 'StartData', 'EndData', ]: raise PTPError( 'Unexpected PTP/IP packet type {}' .format(header.Type) ) if header.Type not in ['StartData', 'Data', 'EndData']: break else: response = self.__parse_response(ipdata) if header.Type == 'StartData': expected = response.TotalDataLength current_transaction = response.TransactionID elif ( header.Type == 'Data' and response.TransactionID == current_transaction ): data += response.Data elif ( header.Type == 'EndData' and response.TransactionID == current_transaction ): data += response.Data datalen = len(data) if datalen != expected: logger.warning( '{} data than expected {}/{}' .format( 'More' if datalen > expected else 'Less', datalen, expected ) ) response['Data'] = data response['Type'] = 'Data' return response if raw: # TODO: Deal with raw Data packets?? return ipdata else: return self.__parse_response(ipdata) def __send(self, ptp_container, event=False): '''Helper method for sending packets.''' packet = self.__Packet.build(ptp_container) ip = ( actual_socket(self.__evtcon) if event else actual_socket(self.__cmdcon) ) while ip.sendall(packet) is not None: logger.debug('Failed to send {} packet'.format(ptp_container.Type)) def __send_request(self, ptp_container): '''Send PTP request without checking answer.''' # Don't modify original container to keep abstraction barrier. ptp = Container(**ptp_container) # Send unused parameters always ptp['Parameter'] += [0] * (5 - len(ptp.Parameter)) # Send request ptp['Type'] = 'Command' ptp['DataphaseInfo'] = 'In' ptp['Payload'] = self.__Command.build(ptp) self.__send(ptp) def __send_data(self, ptp_container, data): '''Send data without checking answer.''' # Don't modify original container to keep abstraction barrier. ptp = Container(**ptp_container) # Send data ptp['Type'] = 'Data' ptp['DataphaseInfo'] = 'Out' ptp['Payload'] = data self.__send(ptp) # Actual implementation # --------------------- def send(self, ptp_container, data): '''Transfer operation with dataphase from initiator to responder''' logger.debug('SEND {}{}'.format( ptp_container.OperationCode, ' ' + str(list(map(hex, ptp_container.Parameter))) if ptp_container.Parameter else '', )) with self.__implicit_session(): with self.__transaction_lock: self.__send_request(ptp_container) self.__send_data(ptp_container, data) # Get response and sneak in implicit SessionID and missing # parameters. return self.__recv() def recv(self, ptp_container): '''Transfer operation with dataphase from responder to initiator.''' logger.debug('RECV {}{}'.format( ptp_container.OperationCode, ' ' + str(list(map(hex, ptp_container.Parameter))) if ptp_container.Parameter else '', )) with self.__implicit_session(): with self.__transaction_lock: self.__send_request(ptp_container) dataphase = self.__recv() if hasattr(dataphase, 'Data'): response = self.__recv() if ( (ptp_container.TransactionID != dataphase.TransactionID) or (ptp_container.SessionID != dataphase.SessionID) or (dataphase.TransactionID != response.TransactionID) or (dataphase.SessionID != response.SessionID) ): raise PTPError( 'Dataphase does not match with requested operation' ) response['Data'] = dataphase.Data return response else: return dataphase def mesg(self, ptp_container): '''Transfer operation without dataphase.''' op = ptp_container['OperationCode'] if op == 'OpenSession': self.__open_implicit_session() with self.__implicit_session(): with self.__transaction_lock: self.__send_request(ptp_container) # Get response and sneak in implicit SessionID and missing # parameters for FullResponse. response = self.__recv() rc = response['ResponseCode'] if op == 'OpenSession': if rc != 'OK': self.__close_implicit_session() elif op == 'CloseSession': if rc == 'OK': self.__close_implicit_session() return response def event(self, wait=False): '''Check event. If `wait` this function is blocking. Otherwise it may return None. ''' evt = None ipdata = None timeout = None if wait else 0.001 if not self.__event_queue.empty(): ipdata = self.__event_queue.get(block=not wait, timeout=timeout) if ipdata is not None: evt = self.__parse_response(ipdata) return evt def __poll_events(self): '''Poll events, adding them to a queue.''' logger.debug('Start') while ( not self.__implicit_session_shutdown.is_set() and self.__implicit_session_open.is_set() and _main_thread_alive() ): try: evt = self.__recv(event=True, wait=False, raw=True) except OSError as e: if e.errno == 9 and not self.__implicit_session_open.is_set(): break else: raise e if evt is not None: logger.debug('Event queued') self.__event_queue.put(evt) sleep(5e-3) logger.debug('Stop') def __ping_pong(self): '''Poll events, adding them to a queue.''' logger.debug('Start') last = time() while ( not self.__implicit_session_shutdown.is_set() and self.__implicit_session_open.is_set() and _main_thread_alive() ): if time() - last > 10: logger.debug('PING') # TODO: implement Ping Pong last = time() sleep(0.10) logger.debug('Stop')
existing_object_header = "header"/Struct( UnitAdapter("object_type"/Int16ul), Padding(2), Padding(4), "hitpoints"/Float32l, Padding(4), "object_id"/Int32ul, Padding(1), "x"/Float32l, "y"/Float32l, ) # Resource-specific header # Note: these fields might exist on non-resources, but be empty (?) resource_header = "resource_header"/Struct( Embedded(existing_object_header), Padding(12), ResourceEnum("resource_type"/Int16sl), "amount"/Float32l, ) # Other - seems to be items under Units > Other in the scenario editor other = "other"/Struct( Embedded(existing_object_header), Padding(32), # The following sections can be refined with further research. # There are clearly some patterns. "has_extra"/Byte, If(lambda ctx: ctx.has_extra == 2, Padding( 34 )),
"Entry" / GreedyBytes ) Certificate = Struct( "Length" / Int24ub, "CertData" / Bytes(this.Length) ) CertificateChain = Struct( "ChainLength" / Int24ub, "Chain" / GreedyRange(Certificate), ) PreCertEntry = Struct( "LeafCert" / Certificate, Embedded(CertificateChain), Terminated ) async def retrieve_all_ctls(session=None): async with session.get(CTL_LISTS) as response: ctl_lists = await response.json() logs = ctl_lists['logs'] for log in logs: if log['url'].endswith('/'): log['url'] = log['url'][:-1] owner = _get_owner(log, ctl_lists['operators']) log['operated_by'] = owner
DATA_STOP=3, SENSOR_MAP=9, DATA_RATE=10), 'sending_node' / Int32ub, # bytes 16-19 # Message data is optional # Previous implementation used If(this._.payload_length > 8, ...), but this # method does not seem to work in v2.8. # message_length: bytes 20-23, message: bytes 24+ 'message' / Optional( PascalString(lengthfield='message_length' / Int32ub, encoding='ascii'))) EEG_data = Struct( 'timestamp' / Float32b, # bytes 12-15 'data_counter' / Int8ub, # byte 16; Unused, just 0 currently 'ADC_status' / Bytes(6), # bytes 17-22 # bytes 23-26, 27-30, etc. 'sensor_data' / Array((this._.payload_length - 11) // 4, Float32b)) null = Struct('none' / Array(111, Int8ub)) packet = Struct( Embedded(header), 'payload' / Embedded( Switch(this.type, { 'NULL': null, 'EVENT': event, 'EEG_DATA': EEG_data })))
def __setup_constructors(self): '''Set endianness and create transport-specific constructors.''' # Set endianness of constructors before using them. self._set_endian('little') self.__Length = Int32ul self.__Type = Enum( Int32ul, Undefined=0x00000000, InitCommand=0x00000001, InitCommandAck=0x00000002, InitEvent=0x00000003, InitEventAck=0x00000004, InitFail=0x00000005, Command=0x00000006, Response=0x00000007, Event=0x00000008, StartData=0x00000009, Data=0x0000000A, Cancel=0x0000000B, EndData=0x0000000C, Ping=0x0000000D, Pong=0x0000000E, ) self.__Header = Struct( 'Length' / self.__Length, 'Type' / self.__Type, ) self.__Param = Range(0, 5, self._Parameter) self.__EventParam = Range(0, 3, self._Parameter) self.__PacketBase = Struct( Embedded(self.__Header), 'Payload' / Bytes( lambda ctx, h=self.__Header: ctx.Length - h.sizeof()), ) self.__Packet = ExprAdapter( self.__PacketBase, encoder=lambda obj, ctx, h=self.__Header: Container( Length=len(obj.Payload) + h.sizeof(), **obj ), decoder=lambda obj, ctx: obj, ) # Yet another arbitrary string type. Max-length CString utf8-encoded self.__PTPIPString = ExprAdapter( RepeatUntil( lambda obj, ctx, lst: six.unichr(obj) in '\x00' or len(lst) == 40, Int16ul ), encoder=lambda obj, ctx: [] if len(obj) == 0 else[ord(c) for c in six.text_type(obj)]+[0], decoder=lambda obj, ctx: u''.join( [six.unichr(o) for o in obj] ).split('\x00')[0], ) # PTP/IP packets # Command self.__ProtocolVersion = Struct( 'Major' / Int16ul, 'Minor' / Int16ul, ) self.__InitCommand = Embedded(Struct( 'InitiatorGUID' / Array(16, Int8ul), 'InitiatorFriendlyName' / self.__PTPIPString, 'InitiatorProtocolVersion' / self.__ProtocolVersion, )) self.__InitCommandACK = Embedded(Struct( 'ConnectionNumber' / Int32ul, 'ResponderGUID' / Array(16, Int8ul), 'ResponderFriendlyName' / self.__PTPIPString, 'ResponderProtocolVersion' / self.__ProtocolVersion, )) # Event self.__InitEvent = Embedded(Struct( 'ConnectionNumber' / Int32ul, )) # Common to Events and Command requests self.__Reason = Enum( # TODO: Verify these codes... Int32ul, Undefined=0x0000, RejectedInitiator=0x0001, Busy=0x0002, Unspecified=0x0003, ) self.__InitFail = Embedded(Struct( 'Reason' / self.__Reason, )) self.__DataphaseInfo = Enum( Int32ul, Undefined=0x00000000, In=0x00000001, Out=0x00000002, ) self.__Command = Embedded(Struct( 'DataphaseInfo' / self.__DataphaseInfo, 'OperationCode' / self._OperationCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__Param, )) self.__Response = Embedded(Struct( 'ResponseCode' / self._ResponseCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__Param, )) self.__Event = Embedded(Struct( 'EventCode' / self._EventCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__EventParam, )) self.__StartData = Embedded(Struct( 'TransactionID' / self._TransactionID, 'TotalDataLength' / Int64ul, )) # TODO: Fix packing and unpacking dataphase data self.__Data = Embedded(Struct( 'TransactionID' / self._TransactionID, 'Data' / Bytes( lambda ctx: ctx._.Length - self.__Header.sizeof() - self._TransactionID.sizeof() ), )) self.__EndData = Embedded(Struct( 'TransactionID' / self._TransactionID, 'Data' / Bytes( lambda ctx: ctx._.Length - self.__Header.sizeof() - self._TransactionID.sizeof() ), )) self.__Cancel = Embedded(Struct( 'TransactionID' / self._TransactionID, )) # Convenience construct for parsing packets self.__PacketPayload = Debugger(Struct( 'Header' / Embedded(self.__Header), 'Payload' / Embedded(Switch( lambda ctx: ctx.Type, { 'InitCommand': self.__InitCommand, 'InitCommandAck': self.__InitCommandACK, 'InitEvent': self.__InitEvent, 'InitFail': self.__InitFail, 'Command': self.__Command, 'Response': self.__Response, 'Event': self.__Event, 'StartData': self.__StartData, 'Data': self.__Data, 'EndData': self.__EndData, }, default=Pass, )) ))
ConfigurationSetGatewayIpAddr = Struct( "gateway_ip_address" / IpAddressAdapter(Bytes(4)), ) ConfigurationSetNetmask = Struct("netmask" / Int8ul, ) ConfigurationSetWithoutOptionalAutoDhcpEnabled = Struct( "mtu_size" / Int16ul, "mac_address" / MacAddressAdapter(Bytes(6)), "server_port_number" / Int16ul, "reconnect_interval" / Int16ul, "server_address_length" / Int8ul, "server_address" / PaddedString(this.server_address_length, "utf8"), ) ConfigurationSetWithOptionalDhcpEnabledWithStaticDns = Struct( Embedded(ConfigurationSetWithoutOptionalAutoDhcpEnabled), "dns_ip_address" / IpAddressAdapter(Bytes(4)), ) ConfigurationSetWithOptionalDhcpDisabled = Struct( Embedded(ConfigurationSetWithOptionalDhcpEnabledWithStaticDns), "ip_address" / IpAddressAdapter(Bytes(4)), "gateway_ip_address" / IpAddressAdapter(Bytes(4)), "netmask" / Int8ul, ) ConfigurationSet = Select( static=ConfigurationSetWithOptionalDhcpDisabled, dns=ConfigurationSetWithOptionalDhcpEnabledWithStaticDns, minimal=ConfigurationSetWithoutOptionalAutoDhcpEnabled, )
Embedded( Switch( this.type, { # type=0x0a, request for other players to propose a player number? "type_hello": Struct("u2" / Default(Int8ub, 1)), # cdjs send 1, djm900nxs sends 3 # type=0x04, publishing a proposed player number, check if anyone else has it? iteration goes 1..2..3 "type_number": Struct("proposed_player_number" / Int8ub, "iteration" / Int8ub), # type=0x00, publishing mac address, iteration goes 1..2..3 again "type_mac": Struct( "iteration" / Int8ub, "u2" / Default(Int8ub, 1), # rekordbox has 4 here "mac_addr" / MacAddr), # type=0x02, publishing ip + mac, iteration goes 1..2..3 again "type_ip": Struct( "ip_addr" / IpAddr, "mac_addr" / MacAddr, "player_number" / Int8ub, "iteration" / Int8ub, "u2" / Default(Int8ub, 1), # rekordbox has 4 here "player_number_assignment" / Default(PlayerNumberAssignment, "manual")), # type=0x06, the standard keepalive packet "type_status": Struct( "player_number" / Int8ub, "u2" / Default( Int8ub, 1 ), # actual player number? sometimes other player's id, sometimes own id "mac_addr" / MacAddr, "ip_addr" / IpAddr, "device_count" / Default(Int8ub, 1), # number of known prodjlink devices Padding(2), "u3" / Default(Int16ub, 1)), # rekordbox has 4 here "type_change": Struct( # when changing player number "old_player_number" / Int8ub, "ip_addr" / IpAddr) })))
CTL_TEMPERATURE_DEFAULT_STATUS = 0x8268 class LightCTLSetupOpcode(IntEnum): CTL_TEMPERATURE_DEFAULT_SET = 0x8269 CTL_TEMPERATURE_DEFAULT_SET_UNACKNOWLEDGED = 0x826A CTL_TEMPERATURE_RANGE_SET = 0x826B CTL_TEMPERATURE_RANGE_SET_UNACKNOWLEDGED = 0x826C LightCTLGet = Struct() LightCTLDefault = Struct("ctl_lightness" / Int16ul, "ctl_temperature" / Int16ul, "ctl_delta_uv" / Int16ul) LightCTLSetMinimal = Struct(Embedded(LightCTLDefault), "tid" / Int8ul) LightCTLSetOptional = Struct(Embedded(LightCTLSetMinimal), Embedded(OptionalSetParameters)) LightCTLSet = Select(LightCTLSetOptional, LightCTLSetMinimal) LightCTLStatusMinimal = Struct( "present_ctl_lightness" / Int16ul, "present_ctl_temperature" / Int16ul, ) LightCTLStatusOptional = Struct( Embedded(LightCTLStatusMinimal), "target_ctl_lightness" / Int16ul, "target_ctl_temperature" / Int16ul, "remaining_time" / TransitionTimeAdapter(TransitionTime, allow_unknown=True))
class GenericLevelOpcode(IntEnum): LEVEL_GET = 0x8205 LEVEL_SET = 0x8206 LEVEL_SET_UNACKNOWLEDGED = 0x8207 LEVEL_STATUS = 0x8208 DELTA_SET = 0x8209 DELTA_SET_UNACKNOWLEDGED = 0x820A MOVE_SET = 0x820B MOVE_SET_UNACKNOWLEDGED = 0x820C GenericLevelGet = Struct() GenericLevelSetMinimal = Struct("level" / Int16ul, "tid" / Int8ul) GenericLevelSetOptional = Struct(Embedded(GenericLevelSetMinimal), Embedded(OptionalSetParameters)) GenericLevelSet = Select(GenericLevelSetOptional, GenericLevelSetMinimal) GenericDeltaSetMinimal = Struct("delta_level" / Int32ul, "tid" / Int8ul) GenericDeltaSetOptional = Struct(Embedded(GenericDeltaSetMinimal), Embedded(OptionalSetParameters)) GenericDeltaSet = Select(GenericDeltaSetOptional, GenericDeltaSetMinimal) GenericMoveSetMinimal = Struct("delta_level" / Int16ul, "tid" / Int8ul) GenericMoveSetOptional = Struct(Embedded(GenericMoveSetMinimal), Embedded(OptionalSetParameters))
) research = "research"/Struct( Padding(3), "building_id"/Int32ul, "player_id"/Int16ul, "next"/Peek( Struct( Padding(6), "check"/Int32sl ) ), IfThenElse(lambda ctx: ctx.next.check == -1, Embedded(Struct( "selected"/Int16ul, "technology_type"/Int32ul, Array(lambda ctx: ctx.selected, "selected_ids"/Int32sl) )), Embedded(Struct( "technology_type"/Int16ul, Array(1, "selected_ids"/Int32sl) )) ) ) sell = "sell"/Struct( "player_id"/Byte, ResourceEnum("resource_type"/Byte), "amount"/Byte, Padding(4) )
# Specialization for loading float data faster TaggedFloat64 = ExprAdapter( Struct(Const(5, Int16ul), 'value'/Float64l), encoder=lambda obj, ctx: Container(value=obj.value), decoder=lambda obj, ctx: obj.value) DataList = Struct( 'size'/Int64ul, LazyField(Array(lambda ctx: ctx.size, TaggedFloat64)), Const('\xc0\xff\xee\x01') # XXX: probably useful ) # XXX: hacks bad_strings = ('\xc0\xff\xee\x01\x00\x00', '\x01#Eg\x00\x00') Property = Struct( 'peek'/Peek(Bytes(6)), Embedded(IfThenElse( this.peek in bad_strings, Padding(6), Struct('label'/VBString, 'TaggedData'/TaggedData))) ) Properties = GreedyRange(Property) LabeledDataList = Struct( 'label'/VBString, Padding(18), 'DataList'/Embedded(DataList) ) DataSet = Struct( 'number'/Int64ul, # XXX: may have more than two. Might use ctx.number to decide? 'LabeledDataList'/Array(2, LabeledDataList), 'Properties'/Properties )