def receive(self, timeout=None): try: if timeout is not None: ready = select([self.sock], [], [], timeout) if self.shutdown_signal: return False if ready[0]: data = self.sock.recv(2048) else: print_warning('Timed out on port {}', self.port) return False else: data = self.sock.recv(2048) if self.shutdown_signal: return False if self.analyze: print_data("Raw response", data.hex()) if not data: print_error("Got 0 bytes from socket") # self.close() return False else: self.decode(data) if self.analyze: self.rpc_walk(consume_incoming=False, verbose=False) self.find_responses() return True except ConnectionResetError: print_error('Server hung up during receive') return False
def rpc_walk(self, consume_incoming=True, verbose=True): # Each section should correspond to a RPC request/reply, # with 2 outgoing protobufs and 2 (or more for propertyget/multipart) incoming, # or an RPC event, with 2 (or more?) incoming, and no outgoing if verbose or len(self.incoming_sections) != 0: print_info('Walking {}', self.name) print_data('=' * 32) if not self.rpc_server_is_phantom: print_warning('RPC server appears to be Spark here') if consume_incoming: for i in range(len(self.incoming_sections)): print_data('-' * 16) incoming_section = self.incoming_sections.popleft() self.rpc_walk_one_section(incoming_section) # Useless? if len(self.incoming_sections) != 0: print_error('There were {} incoming sections remaining', len(self.incoming_sections)) else: for incoming_section in self.incoming_sections: print_data('-' * 16) self.rpc_walk_one_section(incoming_section) if len(self.outgoing_sections) != 0: print_error('There were {} outgoing sections remaining', len(self.outgoing_sections))
def __init__(self, raw_section, time=None): self.warnings = [] self.raw_protobufs = [] self.raw_fields = raw_section self.time = time # Sanity Checks try: self.magic = raw_section[0]['firstbyte'] # Delimiter, always empty if len(raw_section[0]['data']) != 0: self.warnings.append('Field 0 of length {} instead of 0'.format( len(raw_section[0]['data']))) i = 1 # Extra field (+ delimiter) that doesnt decode into protobuf, some kind of uid? if self.magic == 0xC3: self.uid = raw_section[i]['data'] i += 2 else: self.uid = b'' # Remaining fields should all be protobufs for raw_field in raw_section[i:]: self.raw_protobufs.append(raw_field['data']) if raw_field['firstbyte'] != self.magic: self.warnings.append('Magic mismatch {} != {}'.format( raw_field['firstbyte'], self.magic)) if self.warnings: print_warning(self.warnings) except Exception as e: print_error('in Section decode: {} {}', type(e), e) pass
def close(self, arg=None): if self.sock is not None: print_warning('Closing Connection to {} on port {}', self.addr, self.port) self.sock.shutdown(2) self.sock.close() self.file.close() self.sock = None self.file = None
def CallMethod(self, method_descriptor, rpc_controller, request, response_class, done, timeout=2): # For event methods, only register callback, don't send anything if method_descriptor.GetOptions( ).Extensions[dvltMethodOptions].isNotification: # For events, response class is always empty, request class is the actual class of the event self.event_callbacks[method_descriptor.full_name] = ( dvlt_pool.messages[method_descriptor.input_type.full_name], done) else: reqUUID = uuid.uuid4().bytes serviceId = rpc_controller.parent_service.service_id if hasattr( rpc_controller.parent_service, 'service_id') else self.find_service_id( method_descriptor.containing_service) typeId, subTypeId = ( 1, 0xFFFFFFFF) if method_descriptor.name == 'propertyGet' else ( 0, method_descriptor.index) cmm_request = Devialet.CallMeMaybe.Request(serverId=self.serverId, serviceId=serviceId, requestId=reqUUID, type=typeId, subTypeId=subTypeId) # First add the callback to the queue... self.request_queue[reqUUID] = (method_descriptor, response_class, rpc_controller, done if done else self.unblock_call) if done is None: # Blocking Call self.blocked.clear() # ...Then send the actual request bytes self.write_rpc(cmm_request.SerializeToString(), request.SerializeToString()) print_info('Calling method {} from service {} ({})...', method_descriptor.name, rpc_controller.parent_service.serviceName, serviceId) print_data('... with argument:', request) if done is None: # Wait for callback to be executed or socket to die while self.sock is not None and not self.shutdown_signal and not self.blocked.wait( timeout=timeout): # Wait for blocked event to be unset print_warning('Still blocked on method {}...', method_descriptor.full_name) if self.blocking_response is None: # self.close() print_error("Server hung up before response") return self.blocking_response
def close_client(self, addrport): sock, file, c = self.clientsocks.pop(addrport) print_warning('Closing Connection to Client {} on port {}', addrport[0], addrport[1]) try: sock.shutdown(2) except OSError as e: print_error('Error in socket shutdown: {}, already closed?', e) try: sock.close() except OSError as e: print_error('Error in socket clse: {}, already closed?', e) file.close()
def run(self): print_info('Searching for Devialet Device...') while not self.shutdown_signal: ready = select([self.sock], [], [], self.period) if self.shutdown_signal: break if ready[0]: data, (sender_addr, sender_port) = self.sock.recvfrom(1024) if len(data) >= 12: magic, serial_len = struct.unpack('>8sI', data[:12]) serial = data[12:] if magic == b'DVL\x01HERE' and len( data) == 12 + serial_len: if serial not in self.database or self.database[ serial] != sender_addr: self.database[serial] = sender_addr print_info( 'Found Devialet Device with serial {} at address {}', serial, sender_addr) self.queue.put((serial, sender_addr)) if self.callback is not None: self.callback(serial, sender_addr) elif magic == b'DVL\x01BYE!' and len( data) == 12 + serial_len: print_info( 'Device with serial {} at address {} exited', serial, sender_addr) self.database.pop(serial) else: print_warning('Unknown data: {}', data.hex()) # Warning: Unknown data: 44564c014259452100000010066787a949a24d37a99c26d3ff193a5a elif data == b'DVL\x01WHO?': print_info('Got Discovery request') else: print_warning('Discovery message too short: {}', data.hex()) else: if self.advertise: print_info('Advertising...') self.sock.sendto( b'DVL\x01HERE\x00\x00\x00' + bytes([len(self.serial)]) + self.serial, ('255.255.255.255', self.port))
def close(self): rest_incoming = self.incoming_buf.read() rest_outgoing = self.outgoing_buf.read() if rest_incoming: self.warnings.append('Found garbage at end of incoming flow: {}...'.format( ' '.join('{:02x}'.format(x) for x in rest_incoming[:50]))) if rest_outgoing: self.warnings.append('Found garbage at end of outgoing flow: {}...'.format( ' '.join('{:02x}'.format(x) for x in rest_outgoing[:50]))) if self.warnings: print_warning(self.warnings) print_info('flow {} has {} incoming and {} outgoing sections', self.name, len(self.incoming_sections), len(self.outgoing_sections)) self.incoming_buf.close() self.outgoing_buf.close()
def try_to_find_service(self, service_name, port=None): try: ports = self.ports_by_service[service_name] if len(ports) > 1: print_warning( 'More than one possible endpoint match for service {}: {}', service_name, ports) if port is None: port = ports[0] elif port not in ports: print_warning('Requested port not in list of matches') port = ports[0] print_info('Using port {} for service {}', port, service_name) svc_class = dvlt_pool.service_by_name[service_name]._concrete_class client = DevialetClient(name=service_name + ' client', port=port, addr=self.addr) return client, svc_class(client) except KeyError: print_error("Can't find service {} in whatsup services", service_name) pass
def find_requests(self, addrport): flow = self.flows[addrport] while flow.outgoing_sections: outgoing_section = flow.outgoing_sections.popleft() outgoing_pb = outgoing_section.raw_protobufs # print_warning("Found Request") req = Devialet.CallMeMaybe.Request.FromString(outgoing_pb[0]) if req.serverId != self.serverId and req.serverId != b'\x00' * 16: print_warning( 'Oops, this request is not for us (unless this is inital conenction request): we are {}, sent to {}', self.serverId.hex(), req.serverId.hex()) try: srv = self.services[req.serviceId] if req.type == 0: try: method_desc = srv.methods_by_id[req.subTypeId] if method_desc.full_name in self.request_callbacks: (request_class, callback ) = self.request_callbacks[method_desc.full_name] response = callback( request_class.FromString(outgoing_pb[1])) rep = Devialet.CallMeMaybe.Reply( serverId=self.serverId, serviceId=req.serviceId, requestId=req.requestId, type=0, subTypeId=req.subTypeId, errorCode=0, isMultipart=False) self.write_response_to_addr( addrport, rep.SerializeToString(), response.SerializeToString()) else: print_error('Unhandled method {} from {}', method_desc.full_name, addrport) except KeyError: print_errordata( 'Method id {} not in service method dict:'.format( req.subTypeId), { k: v.full_name for (k, v) in srv.methods_by_id.items() }) elif req.type == 1 and req.subTypeId == 0xFFFFFFFF: # PropertyGet special request rep = Devialet.CallMeMaybe.Reply(serverId=self.serverId, serviceId=req.serviceId, requestId=req.requestId, type=1, subTypeId=0xFFFFFFFF, errorCode=0, isMultipart=True) print_info('Got PropertyGet request:') for name, prop in srv.properties.items(): print_data(name, prop) self.write_responses_to_addr( addrport, rep.SerializeToString(), [p.SerializeToString() for p in srv.get_properties()]) elif req.type == 1: # PropertySet special request # TODO print_errordata( 'Unhandled propertyset subtypeId={}'.format( req.subTypeId), [x.hex() for x in outgoing_pb]) pass else: print_error('Unknown request type {}', req.type) except KeyError: print_error( 'Service ID {} not in list {}', req.serviceId, ' '.join(str(self.service_list.services).split('\n'))) self.flows[addrport].outgoing_sections.clear()
def close(self, arg=None): # if self.sock is not None: print_warning('Closing Server Connection on port {}', self.port) self.sock.shutdown(2) self.sock.close()
def service_discovery(self): # if truncated_name not in dvlt_pool.service_by_name: # ports_by_unknown_service.setdefault(truncated_name, []).append(port) # print_data("Services by port", services_by_port) # print_data("Ports by Service", ports_by_service) # print_data("Ports by (Unknown) Service", ports_by_unknown_service) for port, services in self.services_by_port.items(): # if [0 for srvname in services if srvname not in dvlt_pool.service_by_name]: # for service in services: # if srvname not in dvlt_pool.service_by_name: if port not in self.connections: new_conn = DevialetClient(name='Port ' + str(port), addr=self.addr, port=port, start_time=datetime.now()) new_conn.open() self.connections[port] = new_conn # Connect to unknown service for service in new_conn.service_list.services: # Reopen if connection failed if new_conn.sock is None: res = new_conn.reconnect() if not res: break truncated_name = '.'.join( service.name.replace('playthatfunkymusic', 'toomanyflows').split('.')[:-1]) while truncated_name not in dvlt_pool.service_by_name and truncated_name.endswith( '-0'): truncated_name = '.'.join( truncated_name.split('.')[:-1]) print_warning('truncating {} to {}', '.'.join(service.name.split('.')[:-1]), truncated_name) # if truncated_name not in dvlt_pool.service_by_name: # and truncated_name.endswith('-0'): # if (port, truncated_name) not in self.discovered_services and truncated_name not in dvlt_pool.service_by_name: # print_info('Testing 10 methods from service {}', service.name) # for subTypeId in range(10): # result = new_conn.CallUnknownMethod(service.id, subTypeId, Devialet.CallMeMaybe.Empty(), None) # print_data("Response from method id {} from service {}".format(subTypeId, service.name), # result) # if result is None: # break if (port, truncated_name) not in self.discovered_services: if truncated_name in dvlt_pool.service_by_name: srv = dvlt_pool.service_by_name[ truncated_name]._concrete_class(new_conn) srv.watch_properties(service_id=service.id, service_name=service.name) # srv.service_id = service.id # srv.service_name_unique = service.name # srv.propertyGet(DevialetController(srv), Devialet.CallMeMaybe.Empty(), srv.set_properties) # new_conn.keep_receiving(timeout=2) else: result = new_conn.CallUnknownMethod( service.id, 0xFFFFFFFF, Devialet.CallMeMaybe.Empty(), None, typeId=1) print_data( "Unknown properties from service {}".format( service.name), result) pass # new_conn.keep_receiving(timeout=2) new_conn.close() self.connections.pop(port)
def find_responses(self): for i in range(len(self.incoming_sections)): incoming_section = self.incoming_sections.popleft() incoming_pb = incoming_section.raw_protobufs if incoming_section.magic == 0xC3: print_warning("Found Event") # try: evt = Devialet.CallMeMaybe.Event.FromString(incoming_pb[0]) service_name = self.find_service(evt) method, input_pb, outputs_pb = dvlt_pool.process_rpc( service_name, evt, incoming_pb[1], incoming_pb[1:], is_event=True) try: (response_class, callback) = self.event_callbacks[method.full_name] if evt.type == 1: # PropertyUpdate special event callback(evt.subTypeId, incoming_pb[1]) else: callback(response_class.FromString(incoming_pb[1])) except KeyError: print_error('Unhandled event {}', method.full_name) print_errordata('Registered Callbacks', self.event_callbacks) except AttributeError: # method can be none eg when service name not in db pass if incoming_section.uid != self.serverId: print_error('Oops, event from different server Id ?!') # except IndexError: # print_error('not enough incoming protos for event ({}) < 2', len(incoming_pb)) else: try: rep = Devialet.CallMeMaybe.Reply.FromString(incoming_pb[0]) method_descriptor, response_class, controller, callback = self.request_queue.pop( rep.requestId) if rep.errorCode != 0: # print_warning("Got error code: {} ({})", controller.parent_service.get_error(rep.errorCode), rep.errorCode) controller.SetFailed(rep.errorCode) # use errorEnumName, controller... # None is used for unknown method calls if response_class is not None: # PropertyGet special "method" if rep.subTypeId == 0xFFFFFFFF and rep.type == 1: # response = {} # for i, raw in enumerate(incoming_pb[1:]): # name, prop = dvlt_pool.get_property(method_descriptor.containing_service, i, raw) # response[name] = prop response = incoming_pb[1:] else: response = response_class.FromString( incoming_pb[1]) # print_data("Found Response", response) callback(response) else: # print_data('Response with unknown message type:', # dvlt_pool.heuristic_search(incoming_pb[1])) if rep.subTypeId == 0xFFFFFFFF and rep.type == 1: callback([ dvlt_pool.heuristic_search(x) for x in incoming_pb[1:] ]) else: callback(dvlt_pool.heuristic_search( incoming_pb[1])) if not rep.isMultipart and len(incoming_pb) > 2: print_warning( 'we got more incoming protobufs than we should have, not Multipart' ) if len(incoming_pb) < 2: print_error('we got less than 2 incoming protobufs') # print_info('out_time:{} in_time:{} req:{}/{}/{:>10d}/{:>12d}, rep:{}/{}/{:>10d}/{:>12d} {}{}{}', # outgoing_section.time, incoming_section.time, # req.requestId[:4].hex(), req.type, req.subTypeId, req.serviceId, # rep.requestId[:4].hex(), rep.type, rep.subTypeId, rep.serviceId, # 'M' if rep.isMultipart else ' ', # ' ' if method.name == 'ping' else 'C' if method.name == 'openConnection' else '.', # '<' if rep.requestId != req.requestId else ' ') except KeyError: print_error('Response to unknown request id {}', rep.requestId.hex()) print_errordata('Request queue', self.request_queue)
def rpc_walk_one_section(self, incoming_section): incoming_pb = incoming_section.raw_protobufs if incoming_section.magic == 0xC3: # Event? try: evt = dvlt_pool.interpret_as(incoming_pb[0], 'Devialet.CallMeMaybe.Event') service_name = self.find_service(evt) method, input_pb, outputs_pb = dvlt_pool.process_rpc(service_name, evt, incoming_pb[1], incoming_pb[1:], is_event=True) if method.containing_service.full_name == 'Devialet.CallMeMaybe.Connection': if method.name == 'serviceAdded': print_info('Extending list of services') self.service_list.services.add(name=input_pb.name, id=input_pb.id) # The 'uid' parameter in the section, when present (== when magic is C3, and only on incoming packets) # should be equal to the server ID print_info('in_time:{} evt:{} {}/{:>10d}/{:>12d}{:31s} {} E', incoming_section.time, evt.serverId[:4].hex(), evt.type, evt.subTypeId, evt.serviceId, '', incoming_section.uid[:4].hex()) except IndexError: print_error('not enough incoming protos for event ({}) < 2', len(incoming_pb)) except AttributeError: pass else: try: outgoing_section = self.outgoing_sections.popleft() outgoing_pb = outgoing_section.raw_protobufs req = dvlt_pool.interpret_as(outgoing_pb[0], 'Devialet.CallMeMaybe.Request') rep = dvlt_pool.interpret_as(incoming_pb[0], 'Devialet.CallMeMaybe.Reply') bad_reqs = deque() # print('UUID {}'.format(req.requestId.hex())) # (First two bytes (or more) of request id appear to be sequential) while rep.requestId != req.requestId: bad_reqs.appendleft(outgoing_section) print_warning('Request id {} out of order', req.requestId.hex()) # print_errordata('Full Request:', req) try: outgoing_section = self.outgoing_sections.popleft() outgoing_pb = outgoing_section.raw_protobufs req = dvlt_pool.interpret_as(outgoing_pb[0], 'Devialet.CallMeMaybe.Request') except IndexError: # Reached end of outgoing_sections # print_error("Couldn't find request for reply {}", rep.requestId.hex()) break self.outgoing_sections.extendleft(bad_reqs) if not rep.isMultipart and len(incoming_pb) > 2: print_warning('we got more incoming protobufs than we should have, not Multipart') if len(outgoing_pb) > 2: print_error('we got more than 2 outgoing protobufs') if len(outgoing_pb) < 2: print_error('we got less than 2 outgoing protobufs') if len(incoming_pb) < 2: print_error('we got less than 2 incoming protobufs') service_name = self.find_service(rep) method, input_pb, outputs_pb = dvlt_pool.process_rpc( service_name, rep, outgoing_pb[1], incoming_pb[1:]) if method.containing_service.full_name == 'Devialet.CallMeMaybe.Connection': if method.name == 'openConnection': self.service_list = outputs_pb[0] print_info('out_time:{} in_time:{} req:{}/{}/{:>10d}/{:>12d}, rep:{}/{}/{:>10d}/{:>12d} {}{}{}', outgoing_section.time, incoming_section.time, req.requestId[:4].hex(), req.type, req.subTypeId, req.serviceId, rep.requestId[:4].hex(), rep.type, rep.subTypeId, rep.serviceId, 'M' if rep.isMultipart else ' ', ' ' if method.name == 'ping' else 'C' if method.name == 'openConnection' else '.', '<' if rep.requestId != req.requestId else ' ') except IndexError: print_error('Stream ended prematurely, missing outgoing section') except Exception as e: print_error('Unexpected {} {}', type(e), e)
r2.cmd('aaa') # print_info('Finished analysis') sections = json.loads(r2.cmd('Sj')) xrefs = r2.cmd('axF InternalAddGeneratedFile|cut -d" " -f2|sort -u').split() def get_paddr(vaddr): for section in sections: if vaddr >= section['vaddr'] and vaddr < section['vaddr'] + section['size']: return vaddr - section['vaddr'] + section['paddr'] print_error("Can't find virtual address {}", vaddr) return 0 for xref in xrefs: disasm = json.loads(r2.cmd('pdj -2 @ ' + xref)) if disasm[0]['type'] == 'push' and disasm[1]['type'] == 'push': length = disasm[0]['val'] addr = disasm[1]['val'] # print_info('Found protobuf of length {:6d} at addr 0x{:8x}', length, addr) paddr = get_paddr(addr) data = f[paddr:paddr+length] try: fdp = FileDescriptorProto.FromString(data) print_info('Found FiledescriptorProto of length {:6d} at addr 0x{:08x}: {}', length, paddr, fdp.name, color='green') outfile = open(os.path.join(out_dir, fdp.name.replace('/', '_')), 'wb') outfile.write(data) # print(fdp) except google.protobuf.message.DecodeError: print_error('Error while decoding data at offset 0x{:08x}, length {:6d} as FiledescriptorProto', paddr, length) else: print_warning('No push in immediate vicinity')
def __init__(self, filename, spark_addr, phantom_addr, decode_by_flow=False): DevialetManyFlows.__init__(self) self.filename = filename self.spark_addr = spark_addr self.phantom_addr = phantom_addr self.decode_by_flow = decode_by_flow # print_info('Loading file...') # capture = scapy.all.rdpcap(filename) # self.sessions = capture[TCP].sessions() with PcapReader(filename) as pcap_reader: for packet in pcap_reader: # print(packet) if packet.haslayer(TCP): # for packet in capture[TCP]: time = datetime.fromtimestamp(packet.time) # print(packet) # if packet. spark_port = -1 if packet[IP].src == self.spark_addr and packet[IP].dst == self.phantom_addr: spark_port = packet[TCP].sport phantom_port = packet[TCP].dport phantom_to_spark = False elif packet[IP].src == self.phantom_addr and packet[IP].dst == self.spark_addr: spark_port = packet[TCP].dport phantom_port = packet[TCP].sport phantom_to_spark = True if spark_port >= 0: if (phantom_port, spark_port) in self.flows: flow = self.flows[(phantom_port, spark_port)] else: print_warning('New Flow phantom {}, spark {}, time {}', phantom_port, spark_port, time) flow = DevialetFlow(name='phantom {}, spark {}'.format(phantom_port, spark_port), phantom_port=phantom_port, spark_port=spark_port, start_time=time) flow.phantom = SeqData() flow.spark = SeqData() # if first packet is from phantom to spark, rpc server is probably spark if phantom_to_spark: print_info('Found flow where Spark appears to be RPC server: phantom {}, spark {}', phantom_port, spark_port) flow.rpc_server_is_phantom = False self.add_flow(flow) # Reverse direction if rpc server is Spark srv_to_client = phantom_to_spark ^ (not flow.rpc_server_is_phantom) tcplen = packet[IP].len - packet[IP].ihl*4 - packet[TCP].dataofs*4 sending = (flow.phantom if phantom_to_spark else flow.spark) receiving = (flow.spark if phantom_to_spark else flow.phantom) if 'S' in packet.sprintf('%TCP.flags%') or 'F' in packet.sprintf('%TCP.flags%'): # if SYN, synchronize sequence numbers print_info('Sp {:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {}', spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, tcplen, packet[TCP].seq - sending.isn, packet[TCP].ack - receiving.isn, 0, packet.sprintf('%TCP.flags%'), color='red') sending.isn = packet[TCP].seq sending.seq = packet[TCP].seq + 1 if sending.ood: print_error('{} remaining in {} OOD queue', len(sending.ood), 'Phantom' if phantom_to_spark else 'Spark') sending.ood.clear() else: # print(packet[TCP].load[:12].hex()) diff = packet[TCP].seq - sending.seq print_info('Sp {:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {}', spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, tcplen, packet[TCP].seq - sending.isn, packet[TCP].ack - receiving.isn, diff, packet.sprintf('%TCP.flags%'), color='blue' if phantom_to_spark else 'green', reverse=(diff != 0)) if diff == 0: sending.seq = packet[TCP].seq + tcplen if tcplen: flow.decode(packet[TCP].load[:tcplen], time=time, incoming=srv_to_client) if not self.decode_by_flow: flow.rpc_walk(verbose=False) for p in list(sending.ood): l = p[IP].len - p[IP].ihl*4 - p[TCP].dataofs*4 d = p[TCP].seq - sending.seq if d == 0: sending.seq = p[TCP].seq + l if l: flow.decode(p[TCP].load[:l], time=time, incoming=srv_to_client) if not self.decode_by_flow: flow.rpc_walk(verbose=False) sending.ood.remove(p) print_info('Sp {:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {:3} Reordered', spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, l, p[TCP].seq - sending.isn, p[TCP].ack - receiving.isn, d, p.sprintf('%TCP.flags%'), color='magenta') else: # print_warning('{:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {:3} OOD', # spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, l, # p[TCP].seq - sending.isn, p[TCP].ack - receiving.isn, # d, p.sprintf('%TCP.flags%')) pass else: sending.ood.append(packet)
from dvlt_client import WhatsUpClient from dvlt_server import DevialetServer, WhatsUpServer from dvlt_discovery import DevialetDiscovery from queue import Queue # Find a suitable Devialet device hostUid = b'etincelle-' + bytes(uuid.uuid4().hex, 'ascii') target_serial = b'J' discovered = Queue() dscvr = DevialetDiscovery(discovered, serial=hostUid) dscvr.start() serial, dvlt_addr = discovered.get(block=True) while not serial.startswith(target_serial): print_warning('Not who we are looking for') serial, dvlt_addr = discovered.get(block=True) # Open a WhatsUp connection wu_client = WhatsUpClient(name="WhatsUp", addr=dvlt_addr, port=24242) wu_client.go() # Init WhatsUp server wu_srv = WhatsUpServer(hostUid=hostUid) wu_srv.open() # Init AudioSource server putp_server = DevialetServer(wu_srv, hostUid=hostUid) putp_service = Devialet.AudioSource.OnlineSourceSession(putp_server) putp_service.serviceName += '.pickupthepieces' putp_service.properties = {