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)
Beispiel #2
0
 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)
Beispiel #3
0
 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
Beispiel #4
0
    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
Beispiel #6
0
    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))
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #9
0
 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()
Beispiel #11
0
 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
Beispiel #14
0
 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
Beispiel #15
0
    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)
Beispiel #16
0
                                    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]')
Beispiel #17
0
 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
Beispiel #18
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')
Beispiel #19
0
    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))
Beispiel #21
0
    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()