def register_endpoint(self, srv): if (srv.hostUid, srv.port) not in self.endpoints: print_info('Registering endpoint {}', (srv.hostUid, srv.port)) self.endpoints[(srv.hostUid, srv.port)] = srv else: print_error('uid {} port {} already used by endpoint', srv.hostUid, srv.port)
def reconnect(self, timeout=3): count = 0 while not self.open() and count < timeout * 10: time.sleep(.1) count += 1 if count == timeout * 10: print_error('Could not reconnect on port {}', self.port)
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 CallUnknownMethod(self, serviceId, subTypeId, request, done, typeId=0): print_info('Calling unknown method #{} from service #{} on port {}', subTypeId, serviceId, self.port) reqUUID = uuid.uuid4().bytes cmm_request = Devialet.CallMeMaybe.Request(serverId=self.serverId, serviceId=serviceId, requestId=reqUUID, type=typeId, subTypeId=subTypeId) self.request_queue[reqUUID] = (None, None, DevialetController(self.conn), done if done else self.unblock_call) self.write_rpc(cmm_request.SerializeToString(), request.SerializeToString()) if done is None: # Blocking call self.blocking_response = None while self.blocking_response is None and self.receive(): # print_info("Waiting for response on unknown method (serviceId {}, subTypeId {})", # serviceId, subTypeId) # time.sleep(1) pass if self.blocking_response is None: self.close() print_error("Server hung up before response") return self.blocking_response
def open(self): try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Port 0 means system-chosen port self.sock.bind((self.addr, self.port)) self.addr, self.port = self.sock.getsockname() self.sock.listen(5) self.register_service(self.conn) ctrl = DevialetController(self.conn) # Register callback for client connection requests self.conn.openConnection(ctrl, None, self.open_connection) self.conn.ping(ctrl, None, self.pong) # # No Callback - does a blocking RPC # conn_reply = self.conn.openConnection(ctrl, Devialet.CallMeMaybe.ConnectionRequest(version=1), None) # self.serverId = conn_reply.serverId # self.service_list = Devialet.CallMeMaybe.ServicesList(services=conn_reply.services) # # Register event callbacks for added/deleted services # self.conn.serviceAdded(ctrl, None, self.add_service) # self.conn.serviceRemoved(ctrl, None, self.remove_service) # self.conn.serverQuit(ctrl, None, self.close) print_info('Listening on port {}', self.port) # Add to endpoint database of parent whatsup servers self.wu_server.register_endpoint(self) return True except ConnectionRefusedError: exc_type, exc_obj, exc_tb = sys.exc_info() print_error("Can't Connect to {} on port {}, error {}", self.addr, self.port, exc_obj) self.sock = None 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 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 open(self): try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((self.addr, self.port)) self.file = self.sock.makefile(mode='wb') return True except ConnectionRefusedError: exc_type, exc_obj, exc_tb = sys.exc_info() print_error("Can't Connect to {} on port {}, error {}", self.addr, self.port, exc_obj) self.sock = None return False
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 find_service(self, rep): service_name = 'com.devialet.callmemaybe.connection' try: if rep.serviceId != 0 or self.service_list.services: service_lowercase_name = [service.name for service in self.service_list.services if service.id == rep.serviceId][0] # PlayThatFunkyMusic is nowhere in protobufs # service_lowercase_name = service_lowercase_name.replace('playthatfunkymusic', 'toomanyflows') service_name = '.'.join(service_lowercase_name.split('.')[:-1]) while service_name not in dvlt_pool.service_by_name and len(service_name.split('.')) > 1: service_name = '.'.join(service_name.split('.')[:-1]) print_info('truncating {} to {}'.format(service_lowercase_name, service_name)) except IndexError: print_error('Service ID {} not in list {}', rep.serviceId, ' '.join(str(self.service_list.services).split('\n'))) return None return service_name
def find_service_id(self, service_desc): lowercase_name = service_desc.GetOptions( ).Extensions[dvltServiceOptions].serviceName matching_services = [ service.id for service in self.service_list.services if '.'.join(service.name.split('.')[:-1]) == lowercase_name ] try: # Service list not yet populated if lowercase_name == "com.devialet.callmemaybe.connection" and not self.service_list.services: return 0 return matching_services[0] except IndexError: print_error('Service name {} not in list {}', lowercase_name, ' '.join(str(self.service_list.services).split('\n'))) return 0
def get_service_list(self, empty): lst = Devialet.WhatsUp.WhatsUpServicesList() for (hostUid, port), endpoint in self.endpoints.items(): # print_info('listing services for endpoint {}', (hostUid, port)) if hostUid == self.hostUid: for svc_id, svc in endpoint.services.items(): if svc.DESCRIPTOR.full_name != 'Devialet.CallMeMaybe.Connection': lst.services.add( name=svc.serviceName, hostUid=hostUid, localOnly=False, endpoint='tcp://127.0.0.1:{}'.format(port)) else: # TODO: add catalog of other hostuids print_error('Unknown hostUid {}', hostUid) print_data('Got service list request:', lst) return lst
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 __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)
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) if __name__ == '__main__': if len(sys.argv) > 3: filename, spark_addr, phantom_addr = sys.argv[1:4] flows = PcapFlows(filename, spark_addr, phantom_addr, decode_by_flow=False) if flows.decode_by_flow: for flow in sorted([f for f in flows.flows.values()], key=lambda x: x.start_time): flow.rpc_walk(verbose=False) print_data('Pcap Flow stats', sorted( [{ # 'phantom port': pp, # 'spark port': sp, 'ports': f.name, 'start time': str(f.start_time), 'incoming bytes': len(f.incoming_buf.getbuffer()), 'outgoing bytes': len(f.outgoing_buf.getbuffer()) } for (pp, sp), f in flows.flows.items()], key=lambda x: x['start time']) ) else: print_error('Usage: pcap_decode.py [file.pcapng] [spark_addr] [phantom_addr]')
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
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 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)
def deregister_endpoint(self, srv): try: self.endpoints.pop((srv.hostUid, srv.port)) except KeyError: print_error("Can't deregister: {} is not a registered endpoint", (srv.hostUid, srv.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 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()