示例#1
0
    def detect(self, data):
        n, detected_mode = detect_data_format(data)
        if detected_mode is not None:
            log("Detected {mode} format input".format(mode=detected_mode))
            if detected_mode == _modes.AVR:
                log("Input format is AVR with no timestamps. "
                    "This format does not contain enough information for multilateration. "
                    "Please enable mlat timestamps on your receiver.")
                self.close()
                return (0, (), False)

            self.reader.mode = detected_mode
            self.feed = self.reader.feed

            # synthesize a mode-change event before the real messages
            mode_change = (mode_change_event(self.reader), )

            try:
                m, messages, pending_error = self.feed(data[n:])
            except ValueError:
                # return just the mode change and keep the error pending
                return (n, mode_change, True)

            # put the mode change on the front of the message list
            return (n + m, mode_change + messages, pending_error)
        else:
            if len(data) > 512:
                raise ValueError('Unable to autodetect input message format')
            return (0, (), False)
示例#2
0
    def __init__(self, port, connection_factory):
        asyncore.dispatcher.__init__(self)
        self.port = port

        self.a_type = socket.SOCK_STREAM
        try:
            # bind to V6 so we can accept both V4 and V6
            # (asyncore makes it a hassle to bind to more than
            # one address here)
            self.a_family = socket.AF_INET6
            self.create_socket(self.a_family, self.a_type)
        except socket.error:
            # maybe no v6 support?
            self.a_family = socket.AF_INET
            self.create_socket(self.a_family, self.a_type)

        try:
            self.set_reuse_addr()
            self.bind(('', port))
            self.listen(5)
        except:
            self.close()
            raise

        self.output_channels = set()
        self.connection_factory = connection_factory
        log('Listening for {0} on port {1}', connection_factory.describe(), port)
示例#3
0
    def __init__(self, port, connection_factory):
        asyncore.dispatcher.__init__(self)
        self.port = port

        self.a_type = socket.SOCK_STREAM
        try:
            # bind to V6 so we can accept both V4 and V6
            # (asyncore makes it a hassle to bind to more than
            # one address here)
            self.a_family = socket.AF_INET6
            self.create_socket(self.a_family, self.a_type)
        except socket.error:
            # maybe no v6 support?
            self.a_family = socket.AF_INET
            self.create_socket(self.a_family, self.a_type)

        try:
            self.set_reuse_addr()
            self.bind(('', port))
            self.listen(5)
        except:
            self.close()
            raise

        self.output_channels = set()
        self.connection_factory = connection_factory
        log('Listening for {0} on port {1}', connection_factory.describe(),
            port)
示例#4
0
 def log(self, fmt, *args, **kwargs):
     log('{what} with {host}:{port}: ' + fmt,
         *args,
         what=self.describe(),
         host=self.addr[0],
         port=self.addr[1],
         **kwargs)
示例#5
0
    def reconnect(self):
        if self.state != 'disconnected':
            self.disconnect('About to reconnect')

        try:
            self.reset_connection()

            if len(self.addrlist) == 0:
                # ran out of addresses to try, resolve it again
                self.addrlist = socket.getaddrinfo(host=self.host,
                                                   port=self.port,
                                                   family=socket.AF_UNSPEC,
                                                   type=socket.SOCK_STREAM,
                                                   proto=0,
                                                   flags=0)

            # try the next available address
            a_family, a_type, a_proto, a_canonname, a_sockaddr = self.addrlist[
                0]
            del self.addrlist[0]

            self.create_socket(a_family, a_type)
            self.connect(a_sockaddr)
        except socket.error as e:
            log('Connection to {host}:{port} failed: {ex!s}',
                host=self.host,
                port=self.port,
                ex=e)
            self.close()
示例#6
0
    def reconnect(self):
        if self.state != 'disconnected':
            self.disconnect('About to reconnect')

        try:
            self.reset_connection()

            if len(self.addrlist) == 0:
                # ran out of addresses to try, resolve it again
                self.addrlist = socket.getaddrinfo(host=self.host,
                                                   port=self.port,
                                                   family=socket.AF_UNSPEC,
                                                   type=socket.SOCK_STREAM,
                                                   proto=0,
                                                   flags=0)

            # try the next available address
            a_family, a_type, a_proto, a_canonname, a_sockaddr = self.addrlist[0]
            del self.addrlist[0]

            sock = self.create_socket(a_family, a_type)
            self.connect(a_sockaddr)
        except socket.error as e:
            log('Connection to {host}:{port} failed: {ex!s}', host=self.host, port=self.port, ex=e)
            self.close()
示例#7
0
    def periodic_stats(self, now):
        global_stats.log_and_reset(self)

        adsb_req = adsb_total = modes_req = modes_total = 0
        now = monotonic_time()
        for ac in self.aircraft.values():
            if ac.messages < 2:
                continue

            if ac.adsb_good:
                adsb_total += 1
                if ac.requested:
                    adsb_req += 1
            else:
                modes_total += 1
                if ac.requested:
                    modes_req += 1

        log('Aircraft: {modes_req} of {modes_total} Mode S, {adsb_req} of {adsb_total} ADS-B used',
            modes_req=modes_req,
            modes_total=modes_total,
            adsb_req=adsb_req,
            adsb_total=adsb_total)

        if self.recent_jumps > 0:
            log('Out-of-order timestamps: {recent}', recent=self.recent_jumps)
            self.recent_jumps = 0
示例#8
0
 def disconnect(self, reason):
     if self.state != 'disconnected':
         log('Disconnecting from {host}:{port}: {reason}',
             host=self.host,
             port=self.port,
             reason=reason)
         self.close(True)
示例#9
0
    def detect(self, data):
        n, detected_mode = detect_data_format(data)
        if detected_mode is not None:
            log("Detected {mode} format input".format(mode=detected_mode))
            if detected_mode == _modes.AVR:
                log("Input format is AVR with no timestamps. "
                    "This format does not contain enough information for multilateration. "
                    "Please enable mlat timestamps on your receiver.")
                self.close()
                return (0, (), False)

            self.reader.mode = detected_mode
            self.feed = self.reader.feed

            # synthesize a mode-change event before the real messages
            mode_change = (mode_change_event(self.reader), )

            try:
                m, messages, pending_error = self.feed(data[n:])
            except ValueError:
                # return just the mode change and keep the error pending
                return (n, mode_change, True)

            # put the mode change on the front of the message list
            return (n + m, mode_change + messages, pending_error)
        else:
            if len(data) > 512:
                raise ValueError('Unable to autodetect input message format')
            return (0, (), False)
示例#10
0
    def start_connection(self):
        log('Connected to multilateration server at {0}:{1}, handshaking',
            self.host, self.port)
        self.state = 'handshaking'
        self.last_data_received = monotonic_time()

        compress_methods = ['none']
        if self.offer_zlib:
            compress_methods.append('zlib')
            compress_methods.append('zlib2')

        handshake_msg = {
            'version': 3,
            'client_version': mlat.client.version.CLIENT_VERSION,
            'compress': compress_methods,
            'selective_traffic': True,
            'heartbeat': True,
            'return_results': self.return_results,
            'udp_transport': 2 if self.offer_udp else False,
            'return_result_format': 'ecef'
        }
        handshake_msg.update(self.handshake_data)
        if DEBUG:
            log("Handshake: {0}", handshake_msg)
        self.writebuf += (json.dumps(handshake_msg) + '\n').encode(
            'ascii')  # linebuf not used yet
        self.consume_readbuf = self.consume_readbuf_uncompressed
        self.handle_server_line = self.handle_handshake_response
示例#11
0
 def received_timestamp_jump_event(self, message, now):
     self.recent_jumps += 1
     if self.recent_jumps == 10:
         log("Warning: the timestamps provided by your receiver do not seem to be self-consistent. "
             "This can happen if you feed data from multiple receivers to a single mlat-client, which "
             "is not supported; use a separate mlat-client for each receiver."
             )
示例#12
0
    def handle_connected_request(self, request):
        if DEBUG:
            log('Receive: {0}', request)
        if 'start_sending' in request:
            self.coordinator.server_start_sending(
                [int(x, 16) for x in request['start_sending']])
        elif 'stop_sending' in request:
            self.coordinator.server_stop_sending(
                [int(x, 16) for x in request['stop_sending']])
        elif 'heartbeat' in request:
            pass
        elif 'result' in request:
            result = request['result']
            ecef = result.get('ecef')
            if ecef is not None:
                # new format
                lat, lon, alt = mlat.geodesy.ecef2llh(ecef)
                alt = alt / 0.3038  # convert meters to feet
                ecef_cov = result.get('cov')
                if ecef_cov:
                    var_est = ecef_cov[0] + ecef_cov[3] + ecef_cov[5]
                    if var_est >= 0:
                        error_est = math.sqrt(var_est)
                    else:
                        error_est = -1
                else:
                    error_est = -1
                nstations = result['nd']
                callsign = None
                squawk = None
            else:
                lat = result['lat']
                lon = result['lon']
                alt = result['alt']
                error_est = result['gdop'] * 300  # make a guess
                nstations = result['nstations']
                callsign = result['callsign']
                squawk = result['squawk']

            nsvel = result.get('nsvel')
            ewvel = result.get('ewvel')
            vrate = result.get('vrate')

            self.coordinator.server_mlat_result(timestamp=result['@'],
                                                addr=int(result['addr'], 16),
                                                lat=lat,
                                                lon=lon,
                                                alt=alt,
                                                nsvel=nsvel,
                                                ewvel=ewvel,
                                                vrate=vrate,
                                                callsign=callsign,
                                                squawk=squawk,
                                                error_est=error_est,
                                                nstations=nstations,
                                                anon=False,
                                                modeac=False)
        else:
            log('ignoring request from server: {0}', request)
示例#13
0
文件: net.py 项目: na5ss/mlat-client
    def handle_error(self):
        t, v, tb = sys.exc_info()
        if isinstance(v, IOError):
            log("Connection to {host}:{port} lost: {ex!s}", host=self.host, port=self.port, ex=v)
        else:
            log_exc("Unexpected exception on connection to {host}:{port}", host=self.host, port=self.port)

        self.handle_close()
示例#14
0
    def start_connection(self):
        log('Input connected to {0}:{1}', self.host, self.port)
        self.last_data_received = monotonic_time()
        self.state = 'connected'
        self.coordinator.input_connected()

        # synthesize a mode change immediately if we are not autodetecting
        if self.reader.mode is not None:
            self.coordinator.input_received_messages((mode_change_event(self.reader),))
示例#15
0
    def handle_accept(self):
        accepted = self.accept()
        if not accepted:
            return

        new_socket, address = accepted
        log('Accepted {0} from {1}:{2}', self.connection_factory.describe(), address[0], address[1])

        self.output_channels.add(self.connection_factory(self, new_socket, self.a_type, self.a_family, address))
示例#16
0
    def handle_accept(self):
        accepted = self.accept()
        if not accepted:
            return

        new_socket, address = accepted
        log('Accepted {0} from {1}:{2}', self.connection_factory.describe(), address[0], address[1])

        self.output_channels.add(self.connection_factory(self, new_socket, address))
示例#17
0
    def handle_read(self):
        try:
            moredata = self.recv(16384)
        except socket.error as e:
            if e.errno == errno.EAGAIN:
                return
            raise

        if not moredata:
            self.close()
            return

        global_stats.receiver_rx_bytes += len(moredata)

        self.coordinator.copy_received_messages(moredata)

        if self.residual:
            moredata = self.residual + moredata

        self.last_data_received = monotonic_time()

        try:
            consumed, messages, pending_error = self.feed(moredata)
        except ValueError as e:
            log("Parsing receiver data failed: {e}", e=str(e))
            self.reconnect_interval = 5.0
            self.close()
            return

        if consumed < len(moredata):
            self.residual = moredata[consumed:]
            if len(self.residual) > 5120:
                raise RuntimeError('parser broken - buffer not being consumed')
        else:
            self.residual = None

        global_stats.receiver_rx_messages += self.reader.received_messages
        global_stats.receiver_rx_filtered += self.reader.suppressed_messages
        self.reader.received_messages = self.reader.suppressed_messages = 0

        if messages:
            self.coordinator.input_received_messages(messages)

        if pending_error:
            # call it again to get the exception
            # now that we've handled all the messages
            try:
                if self.residual is None:
                    self.feed(b'')
                else:
                    self.feed(self.residual)
            except ValueError as e:
                log("Parsing receiver data failed: {e}", e=str(e))
                self.close()
                return
示例#18
0
    def consume_readbuf_uncompressed(self):
        lines = self.readbuf.split(b'\n')
        self.readbuf = lines[-1]
        for line in lines[:-1]:
            try:
                msg = json.loads(line.decode('ascii'))
            except ValueError:
                log("json parsing problem, line: >>{line}<<", line=line)
                raise

            self.handle_server_line(msg)
示例#19
0
    def start_connection(self):
        log('Input connected to {0}:{1}', self.host, self.port)
        self.last_data_received = monotonic_time()
        self.state = 'connected'
        self.coordinator.input_connected()

        # synthesize a mode change immediately if we are not autodetecting
        if self.reader.mode is not None:
            self.coordinator.input_received_messages((mode_change_event(self.reader),))

        self.send_settings_message()
示例#20
0
 def received_timestamp_jump_event(self, message, now):
     self.recent_jumps += 1
     self.server.send_clock_jump()
     #log("clockjump")
     if self.recent_jumps % 9 == 8 and time.monotonic(
     ) > self.last_jump_message + 300.0:
         self.last_jump_message = time.monotonic()
         log("WARNING: the timestamps provided by your receiver do not seem to be self-consistent. "
             "This can happen if you feed data from multiple receivers to a single mlat-client, which "
             "is not supported; use a separate mlat-client for each receiver."
             )
示例#21
0
文件: net.py 项目: na5ss/mlat-client
    def reconnect(self):
        if self.state != "disconnected":
            self.disconnect("About to reconnect")

        try:
            self.reset_connection()
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self.connect((self.host, self.port))
        except socket.error as e:
            log("Connection to {host}:{port} failed: {ex!s}", host=self.host, port=self.port, ex=e)
            self.close()
示例#22
0
    def handle_connected_request(self, request):
        if DEBUG:
            log('Receive: {0}', request)
        if 'start_sending' in request:
            self.coordinator.server_start_sending([int(x, 16) for x in request['start_sending']])
        elif 'stop_sending' in request:
            self.coordinator.server_stop_sending([int(x, 16) for x in request['stop_sending']])
        elif 'heartbeat' in request:
            pass
        elif 'result' in request:
            result = request['result']
            ecef = result.get('ecef')
            if ecef is not None:
                # new format
                lat, lon, alt = mlat.geodesy.ecef2llh(ecef)
                alt = alt / 0.3038   # convert meters to feet
                ecef_cov = result.get('cov')
                if ecef_cov:
                    var_est = ecef_cov[0] + ecef_cov[3] + ecef_cov[5]
                    if var_est >= 0:
                        error_est = math.sqrt(var_est)
                    else:
                        error_est = -1
                else:
                    error_est = -1
                nstations = result['nd']
                callsign = None
                squawk = None
            else:
                lat = result['lat']
                lon = result['lon']
                alt = result['alt']
                error_est = result['gdop'] * 300   # make a guess
                nstations = result['nstations']
                callsign = result['callsign']
                squawk = result['squawk']

            self.coordinator.server_mlat_result(timestamp=result['@'],
                                                addr=int(result['addr'], 16),
                                                lat=lat,
                                                lon=lon,
                                                alt=alt,
                                                nsvel=None,
                                                ewvel=None,
                                                vrate=None,
                                                callsign=callsign,
                                                squawk=squawk,
                                                error_est=error_est,
                                                nstations=nstations,
                                                anon=False,
                                                modeac=False)
        else:
            log('ignoring request from server: {0}', request)
示例#23
0
    def handle_read(self):
        try:
            moredata = self.recv(16384)
        except socket.error as e:
            if e.errno == errno.EAGAIN:
                return
            raise

        if not moredata:
            self.close()
            return

        global_stats.receiver_rx_bytes += len(moredata)

        if self.residual:
            moredata = self.residual + moredata

        self.last_data_received = monotonic_time()

        try:
            consumed, messages, pending_error = self.feed(moredata)
        except ValueError as e:
            log("Parsing receiver data failed: {e}", e=str(e))
            self.close()
            return

        if consumed < len(moredata):
            self.residual = moredata[consumed:]
            if len(self.residual) > 5120:
                raise RuntimeError('parser broken - buffer not being consumed')
        else:
            self.residual = None

        global_stats.receiver_rx_messages += self.reader.received_messages
        global_stats.receiver_rx_filtered += self.reader.suppressed_messages
        self.reader.received_messages = self.reader.suppressed_messages = 0

        if messages:
            self.coordinator.input_received_messages(messages)

        if pending_error:
            # call it again to get the exception
            # now that we've handled all the messages
            try:
                if self.residual is None:
                    self.feed(b'')
                else:
                    self.feed(self.residual)
            except ValueError as e:
                log("Parsing receiver data failed: {e}", e=str(e))
                self.close()
                return
示例#24
0
    def close(self, manual_close=False):
        asyncore.dispatcher.close(self)

        if self.state != 'disconnected':
            if not manual_close:
                log('Lost connection to {host}:{port}', host=self.host, port=self.port)

            self.state = 'disconnected'
            self.reset_connection()
            self.lost_connection()

        if not manual_close:
            self.schedule_reconnect()
示例#25
0
    def refresh_socket(self):
        try:
            self.sock.connect(self.remote_address)
        except OSError:
            pass
        except socket.error:
            pass

        new_mtu = get_mtu(self.sock)
        if new_mtu is not None and new_mtu != self.route_mtu:
            util.log('Route MTU changed to {0}', new_mtu)
            self.route_mtu = new_mtu
            self.mtu = max(100, self.route_mtu - 100)
示例#26
0
    def __init__(self, port, connection_factory):
        asyncore.dispatcher.__init__(self)
        self.port = port

        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(('', port))
        self.listen(0)

        self.output_channels = set()
        self.connection_factory = connection_factory

        log('Listening for {0} on port {1}', connection_factory.describe(), port)
示例#27
0
    def handle_error(self):
        t, v, tb = sys.exc_info()
        if isinstance(v, IOError):
            log('Connection to {host}:{port} lost: {ex!s}',
                host=self.host,
                port=self.port,
                ex=v)
        else:
            log_exc('Unexpected exception on connection to {host}:{port}',
                    host=self.host,
                    port=self.port)

        self.handle_close()
示例#28
0
    def consume_readbuf_uncompressed(self):
        lines = self.readbuf.split(b'\n')
        self.readbuf = lines[-1]
        for line in lines[:-1]:
            try:
                msg = json.loads(line.decode('ascii'))
            except ValueError:
                log("json parsing problem, line: >>{line}<<", line=line)
                raise

            if DEBUG:
                log('Receive: {0}', msg)
            self.handle_server_line(msg)
示例#29
0
 def received_mode_change_event(self, message, now):
     # decoder mode changed, clock parameters possibly changed
     self.freq = message.eventdata['frequency']
     self.recent_jumps = 0
     self.server.send_clock_reset(
         reason='Decoder mode changed to {mode}'.format(
             mode=message.eventdata['mode']),
         frequency=message.eventdata['frequency'],
         epoch=message.eventdata['epoch'],
         mode=message.eventdata['mode'])
     log("Input format changed to {mode}, {freq:.0f}MHz clock",
         mode=message.eventdata['mode'],
         freq=message.eventdata['frequency'] / 1e6)
示例#30
0
    def periodic_stats(self, now):
        log('Receiver status: {0}', self.receiver.state)
        log('Server status:   {0}', self.server.state)
        global_stats.log_and_reset()

        adsb_req = adsb_total = modes_req = modes_total = 0
        now = monotonic_time()
        for ac in self.aircraft.values():
            if ac.messages < 2:
                continue

            if now - ac.last_position_time < self.position_expiry_age:
                adsb_total += 1
                if ac.requested:
                    adsb_req += 1
            else:
                modes_total += 1
                if ac.requested:
                    modes_req += 1

        log('Aircraft: {modes_req} of {modes_total} Mode S, {adsb_req} of {adsb_total} ADS-B used',
            modes_req=modes_req,
            modes_total=modes_total,
            adsb_req=adsb_req,
            adsb_total=adsb_total)

        if self.recent_jumps > 0:
            log('Out-of-order timestamps: {recent}', recent=self.recent_jumps)
            self.recent_jumps = 0
示例#31
0
    def periodic_stats(self, now):
        log('Receiver status: {0}', self.receiver.state)
        log('Server status:   {0}', self.server.state)
        global_stats.log_and_reset()

        adsb_req = adsb_total = modes_req = modes_total = 0
        now = monotonic_time()
        for ac in self.aircraft.values():
            if ac.messages < 2:
                continue

            if now - ac.last_position_time < self.position_expiry_age:
                adsb_total += 1
                if ac.requested:
                    adsb_req += 1
            else:
                modes_total += 1
                if ac.requested:
                    modes_req += 1

        log('Aircraft: {modes_req} of {modes_total} Mode S, {adsb_req} of {adsb_total} ADS-B used',
            modes_req=modes_req,
            modes_total=modes_total,
            adsb_req=adsb_req,
            adsb_total=adsb_total)

        if self.recent_jumps > 0:
            log('Out-of-order timestamps: {recent}', recent=self.recent_jumps)
            self.recent_jumps = 0
示例#32
0
    def start_connection(self):
        log('Input connected to {0}:{1}', self.host, self.port)
        self.last_data_received = monotonic_time()
        self.state = 'connected'
        self.coordinator.input_connected()

        # synthesize a mode change immediately if we are not autodetecting
        if self.reader.mode is not None:
            self.coordinator.input_received_messages((mode_change_event(self.reader),))

        # if we are connected to something that is Beast-like (or autodetecting), send a beast settings message
        if self.reader.mode in (None, _modes.BEAST, _modes.RADARCAPE, _modes.RADARCAPE_EMULATED):
            # Binary format, no filters, CRC checks enabled, mode A/C disabled
            settings_message = b'\x1a1C\x1a1d\x1a1f\x1a1j'
            self.send(settings_message)
示例#33
0
    def schedule_reconnect(self):
        if self.reconnect_at is None:
            if len(self.addrlist) > 0:
                # we still have more addresses to try
                # nb: asyncore breaks in odd ways if you try
                # to reconnect immediately at this point
                # (pending events for the old socket go to
                # the new socket) so do it in 0.5s time
                # so the caller can clean up the old
                # socket and discard the events.
                interval = 0.5
            else:
                interval = self.reconnect_interval

            log('Reconnecting in {0} seconds', interval)
            self.reconnect_at = monotonic_time() + interval
示例#34
0
    def schedule_reconnect(self):
        if self.reconnect_at is None:
            if len(self.addrlist) > 0:
                # we still have more addresses to try
                # nb: asyncore breaks in odd ways if you try
                # to reconnect immediately at this point
                # (pending events for the old socket go to
                # the new socket) so do it in 0.5s time
                # so the caller can clean up the old
                # socket and discard the events.
                interval = 0.5
            else:
                interval = self.reconnect_interval

            log('Reconnecting in {0} seconds', interval)
            self.reconnect_at = monotonic_time() + interval
示例#35
0
    def close(self, manual_close=False):
        try:
            asyncore.dispatcher.close(self)
        except AttributeError:
            # blarg, try to eat asyncore bugs
            pass

        if self.state != 'disconnected':
            if not manual_close:
                log('Lost connection to {host}:{port}', host=self.host, port=self.port)

            self.state = 'disconnected'
            self.reset_connection()
            self.lost_connection()

        if not manual_close:
            self.schedule_reconnect()
示例#36
0
    def close(self, manual_close=False):
        try:
            asyncore.dispatcher.close(self)
        except AttributeError:
            # blarg, try to eat asyncore bugs
            pass

        if self.state != 'disconnected':
            if not manual_close:
                log('Lost connection to {host}:{port}', host=self.host, port=self.port)

            self.state = 'disconnected'
            self.reset_connection()
            self.lost_connection()

        if not manual_close:
            self.schedule_reconnect()
示例#37
0
def main():
    # piaware will timestamp our log messages itself, suppress the normal logging timestamps
    mlat.client.util.suppress_log_timestamps = True

    parser = argparse.ArgumentParser(description="Client for multilateration.")

    options.make_inputs_group(parser)
    options.make_results_group(parser)

    parser.add_argument(
        '--udp-transport',
        help=
        "Provide UDP transport information. Expects an IP:port:key argument.",
        required=True)

    args = parser.parse_args()

    log("fa-mlat-client {version} starting up",
        version=mlat.client.version.CLIENT_VERSION)

    # udp_transport is IP:port:key
    # split backwards to handle IPv6 addresses in the host part, which themselves contain colons.
    parts = args.udp_transport.split(':')
    udp_key = int(parts[-1])
    udp_port = int(parts[-2])
    udp_host = ':'.join(parts[:-2])
    udp_transport = UdpServerConnection(udp_host, udp_port, udp_key)
    log("Using UDP transport to {host} port {port}",
        host=udp_host,
        port=udp_port)

    receiver = options.build_receiver_connection(args)
    adept = AdeptConnection(udp_transport,
                            allow_anon=args.allow_anon_results,
                            allow_modeac=args.allow_modeac_results)
    outputs = options.build_outputs(args)

    coordinator = Coordinator(receiver=receiver,
                              server=adept,
                              outputs=outputs,
                              freq=options.clock_frequency(args),
                              allow_anon=args.allow_anon_results,
                              allow_modeac=args.allow_modeac_results)
    adept.start(coordinator)
    coordinator.run_until(lambda: adept.closed)
示例#38
0
def build_outputs(args):
    outputs = []
    for s in args.results:
        try:
            factory = output_factory(s)
        except ValueError as e:
            log("Warning: Ignoring bad results output option '{0}': {1}", s,
                str(e))
            continue

        try:
            output = factory()
        except Exception as e:
            log("Warning: Could not create results output '{0}': {1}", s,
                str(e))
            continue

        outputs.append(output)

    return outputs
示例#39
0
def build_outputs(args):
    outputs = []
    for s in args.results:
        try:
            factory = output_factory(s)
        except ValueError as e:
            log("Warning: Ignoring bad results output option '{0}': {1}",
                s, str(e))
            continue

        try:
            output = factory()
        except Exception as e:
            log("Warning: Could not create results output '{0}': {1}",
                s, str(e))
            continue

        outputs.append(output)

    return outputs
示例#40
0
def altitude(s):
    if s.endswith('m'):
        alt = float(s[:-1])
    elif s.endswith('ft'):
        alt = float(s[:-2]) * 0.3048
    else:
        alt = float(s)

    # Wikipedia to the rescue!
    # "The lowest point on dry land is the shore of the Dead Sea [...]
    # 418m below sea level". Perhaps not the best spot for a receiver?
    # La Rinconada, Peru, pop. 30,000, is at 5100m.
    if s == '60440ft':
        log('<3>Altitude not configured, please configure and reboot')
        time.sleep(3600)
        raise SystemExit

    if alt < -420 or alt > 5100:
        raise argparse.ArgumentTypeError(
            'Altitude %s must be in the range -420m to 6000m' % s)
    return alt
示例#41
0
    def start_connection(self):
        log('Connected to multilateration server at {0}:{1}, handshaking', self.host, self.port)
        self.state = 'handshaking'
        self.last_data_received = monotonic_time()

        compress_methods = ['none']
        if self.offer_zlib:
            compress_methods.append('zlib')
            compress_methods.append('zlib2')

        handshake_msg = {'version': 3,
                         'client_version': mlat.client.version.CLIENT_VERSION,
                         'compress': compress_methods,
                         'selective_traffic': True,
                         'heartbeat': True,
                         'return_results': self.return_results,
                         'udp_transport': 2 if self.offer_udp else False,
                         'return_result_format': 'ecef'}
        handshake_msg.update(self.handshake_data)
        self.writebuf += (json.dumps(handshake_msg) + '\n').encode('ascii')   # linebuf not used yet
        self.consume_readbuf = self.consume_readbuf_uncompressed
        self.handle_server_line = self.handle_handshake_response
示例#42
0
    def start_connection(self):
        log('Connected to multilateration server at {0}:{1}, handshaking',
            self.host, self.port)
        self.state = 'handshaking'
        self.last_data_received = monotonic_time()

        compress_methods = ['none']
        if self.offer_zlib:
            compress_methods.append('zlib')
            compress_methods.append('zlib2')

        uuid = None
        for path in self.uuid_path:
            try:
                with open(path) as file:
                    uuid = file.readline().rstrip('\n')
                break
            except Exception:
                pass

        handshake_msg = {
            'version': 3,
            'client_version': mlat.client.version.CLIENT_VERSION,
            'compress': compress_methods,
            'selective_traffic': True,
            'heartbeat': True,
            'return_results': self.return_results,
            'udp_transport': 2 if self.offer_udp else False,
            'return_result_format': 'ecef',
            'uuid': uuid
        }
        handshake_msg.update(self.handshake_data)
        if DEBUG:
            log("Handshake: {0}", handshake_msg)
        self.writebuf += (json.dumps(handshake_msg, sort_keys=True) +
                          16 * '        ' + '\n').encode(
                              'ascii')  # linebuf not used yet
        self.consume_readbuf = self.consume_readbuf_uncompressed
        self.handle_server_line = self.handle_handshake_response
示例#43
0
    def consume_readbuf_zlib(self):
        i = 0
        while i + 2 < len(self.readbuf):
            hlen, = struct.unpack_from('!H', self.readbuf, i)
            end = i + 2 + hlen
            if end > len(self.readbuf):
                break

            packet = self.readbuf[i + 2:end] + b'\x00\x00\xff\xff'
            linebuf = self.decompressor.decompress(packet)
            lines = linebuf.split(b'\n')
            for line in lines[:-1]:
                try:
                    msg = json.loads(line.decode('ascii'))
                except ValueError:
                    log("json parsing problem, line: >>{line}<<", line=line)
                    raise

                self.handle_server_line(msg)

            i = end

        del self.readbuf[:i]
示例#44
0
    def consume_readbuf_zlib(self):
        i = 0
        while i + 2 < len(self.readbuf):
            hlen, = struct.unpack_from('!H', self.readbuf, i)
            end = i + 2 + hlen
            if end > len(self.readbuf):
                break

            packet = self.readbuf[i + 2:end] + b'\x00\x00\xff\xff'
            linebuf = self.decompressor.decompress(packet)
            lines = linebuf.split(b'\n')
            for line in lines[:-1]:
                try:
                    msg = json.loads(line.decode('ascii'))
                except ValueError:
                    log("json parsing problem, line: >>{line}<<", line=line)
                    raise

                self.handle_server_line(msg)

            i = end

        del self.readbuf[:i]
示例#45
0
    def reconnect(self):
        if self.state != 'disconnected':
            self.disconnect('About to reconnect')

        try:
            self.reset_connection()

            if len(self.addrlist) == 0:
                # ran out of addresses to try, resolve it again
                if self.host == 'feed.adsbexchange.com' and self.basePort == 31090:
                    for index, port in enumerate(self.adsbexchangePorts):
                        if self.port == port:
                            self.port = self.adsbexchangePorts[(index + 1) % len(self.adsbexchangePorts)]
                            break

                #if self.host == 'feed.adsbexchange.com' and self.basePort != self.port:
                #    log('Connecting to {host}:{port} (trying hard-coded alternate port for adsbexchange)', host=self.host, port=self.port)
                #else:
                #    log('Connecting to {host}:{port}', host=self.host, port=self.port)

                self.addrlist = socket.getaddrinfo(host=self.host,
                                                   port=self.port,
                                                   family=socket.AF_UNSPEC,
                                                   type=socket.SOCK_STREAM,
                                                   proto=0,
                                                   flags=0)

            # try the next available address
            a_family, a_type, a_proto, a_canonname, a_sockaddr = self.addrlist[0]
            del self.addrlist[0]

            self.create_socket(a_family, a_type)
            self.connect(a_sockaddr)
        except socket.error as e:
            log('Connection to {host}:{port} failed: {ex!s}', host=self.host, port=self.port, ex=e)
            self.close()
示例#46
0
 def log_and_reset(self):
     now = monotonic_time()
     elapsed = now - self.start
     log('Receiver: {0:6.1f} msg/s received     {1:4.1f}kB/s from receiver',
         self.receiver_rx_messages / elapsed,
         self.receiver_rx_bytes / elapsed / 1000.0)
     log('Server:   {0:6.1f} kB/s from server   {1:4.1f}kB/s TCP to server  {2:4.1f}kB/s UDP to server',
         self.server_rx_bytes / elapsed / 1000.0,
         self.server_tx_bytes / elapsed / 1000.0,
         self.server_udp_bytes / elapsed / 1000.0)
     if self.mlat_positions:
         log('Results:  {0:3.1f} positions/minute',
             self.mlat_positions / elapsed * 60.0)
     self.reset(now)
示例#47
0
    def log_and_reset(self):
        now = monotonic_time()
        elapsed = now - self.start

        processed = self.receiver_rx_messages - self.receiver_rx_filtered
        log(
            'Receiver: {0:6.1f} msg/s received     {1:6.1f} msg/s processed ({2:.0f}%)',
            self.receiver_rx_messages / elapsed, processed / elapsed,
            0 if self.receiver_rx_messages == 0 else 100.0 * processed /
            self.receiver_rx_messages)
        if self.receiver_rx_mlat:
            log(
                'WARNING: Ignored {0:5d} messages with MLAT magic timestamp (do you have --forward-mlat on?)',
                self.receiver_rx_mlat)
        log(
            'Server:   {0:6.1f} kB/s from server   {1:4.1f}kB/s TCP to server  {2:6.1f}kB/s UDP to server',
            self.server_rx_bytes / elapsed / 1000.0,
            self.server_tx_bytes / elapsed / 1000.0,
            self.server_udp_bytes / elapsed / 1000.0)
        if self.mlat_positions:
            log('Results:  {0:3.1f} positions/minute',
                self.mlat_positions / elapsed * 60.0)
        self.reset(now)
示例#48
0
    def log_and_reset(self):
        now = monotonic_time()
        elapsed = now - self.start

        processed = self.receiver_rx_messages - self.receiver_rx_filtered
        log('Receiver: {0:6.1f} msg/s received     {1:6.1f} msg/s processed ({2:.0f}%)',
            self.receiver_rx_messages / elapsed,
            processed / elapsed,
            0 if self.receiver_rx_messages == 0 else 100.0 * processed / self.receiver_rx_messages)
        log('Server:   {0:6.1f} kB/s from server   {1:4.1f}kB/s TCP to server  {2:6.1f}kB/s UDP to server',
            self.server_rx_bytes / elapsed / 1000.0,
            self.server_tx_bytes / elapsed / 1000.0,
            self.server_udp_bytes / elapsed / 1000.0)
        if self.mlat_positions:
            log('Results:  {0:3.1f} positions/minute',
                self.mlat_positions / elapsed * 60.0)
        self.reset(now)
示例#49
0
    def log_and_reset(self, coordinator):
        now = monotonic_time()
        elapsed = now - self.start

        #log('Receiver status: {0}', coordinator.receiver.state)
        #log('Server status:   {0}', coordinator.server.state)

        processed = self.receiver_rx_messages - self.receiver_rx_filtered
        log(
            'Receiver: {3:10s} {0:6.1f} msg/s received     {1:6.1f} msg/s processed ({2:.0f}%)',
            self.receiver_rx_messages / elapsed, processed / elapsed,
            0 if self.receiver_rx_messages == 0 else 100.0 * processed /
            self.receiver_rx_messages, coordinator.receiver.state)
        if self.receiver_rx_mlat:
            log(
                'WARNING: Ignored {0:5d} messages with MLAT magic timestamp (do you have --forward-mlat on?)',
                self.receiver_rx_mlat)
        log(
            'Server:   {0:10s} {1:6.1f} kB/s from server   {2:6.1f} kB/s to server',
            coordinator.server.state, self.server_rx_bytes / elapsed / 1000.0,
            (self.server_tx_bytes + self.server_udp_bytes) / elapsed / 1000.0)
        log('Results:  {0:3.1f} positions/minute',
            self.mlat_positions / elapsed * 60.0)
        self.reset(now)
示例#50
0
    def log_and_reset(self):
        now = monotonic_time()
        elapsed = now - self.start

        processed = self.receiver_rx_messages - self.receiver_rx_filtered
        log(
            'Receiver: {0:6.1f} msg/s received     {1:6.1f} msg/s processed ({2:.0f}%)',
            self.receiver_rx_messages / elapsed, processed / elapsed,
            0 if self.receiver_rx_messages == 0 else 100.0 * processed /
            self.receiver_rx_messages)
        log(
            'Server:   {0:6.1f} kB/s from server   {1:4.1f}kB/s TCP to server  {2:6.1f}kB/s UDP to server',
            self.server_rx_bytes / elapsed / 1000.0,
            self.server_tx_bytes / elapsed / 1000.0,
            self.server_udp_bytes / elapsed / 1000.0)
        if self.mlat_positions:
            log('Results:  {0:3.1f} positions/minute',
                self.mlat_positions / elapsed * 60.0)
        self.reset(now)
示例#51
0
    def handle_read(self):
        try:
            moredata = self.recv(16384)
        except socket.error as e:
            if e.errno == errno.EAGAIN:
                return
            raise

        if not moredata:
            self.close()
            return

        global_stats.receiver_rx_bytes += len(moredata)

        if self.residual:
            moredata = self.residual + moredata

        self.last_data_received = monotonic_time()

        try:
            consumed, messages = self.packetize(moredata, self.last_timestamp)
        except _modes.ClockResetError as e:
            log("Problem reading receiver messages: " + str(e))
            log("Ensure that only one receiver is feeding data to this client.")
            log("A single multilateration client cannot handle data from multiple receivers.")
            self.close()
            return

        if consumed < len(moredata):
            self.residual = moredata[consumed:]
            if len(self.residual) > 5120:
                raise RuntimeError('parser broken - buffer not being consumed')
        else:
            self.residual = None

        if messages:
            global_stats.receiver_rx_messages += len(messages)
            self.last_timestamp = messages[-1].timestamp
            self.coordinator.input_received_messages(messages)
示例#52
0
 def log(self, message):
     log('{0}', message)
示例#53
0
 def start_connection(self):
     log('Input connected to {0}:{1}', self.host, self.port)
     self.last_data_received = monotonic_time()
     self.state = 'ready'
     self.coordinator.input_connected()
示例#54
0
    def handle_handshake_response(self, response):
        if 'reconnect_in' in response:
            self.reconnect_interval = response['reconnect_in']

        if 'deny' in response:
            log('Server explicitly rejected our connection, saying:')
            for reason in response['deny']:
                log('  {0}', reason)
            raise IOError('Server rejected our connection attempt')

        if 'motd' in response:
            log('Server says: {0}', response['motd'])

        compress = response.get('compress', 'none')
        if response['compress'] == 'none':
            self.fill_writebuf = self.fill_uncompressed
            self.consume_readbuf = self.consume_readbuf_uncompressed
        elif response['compress'] == 'zlib' and self.offer_zlib:
            self.compressor = zlib.compressobj(1)
            self.fill_writebuf = self.fill_zlib
            self.consume_readbuf = self.consume_readbuf_uncompressed
        elif response['compress'] == 'zlib2' and self.offer_zlib:
            self.compressor = zlib.compressobj(1)
            self.decompressor = zlib.decompressobj()
            self.fill_writebuf = self.fill_zlib
            self.consume_readbuf = self.consume_readbuf_zlib
        else:
            raise IOError('Server response asked for a compression method {0}, which we do not support'.format(
                response['compress']))

        self.server_heartbeat_at = monotonic_time() + self.heartbeat_interval

        if 'udp_transport' in response:
            host, port, key = response['udp_transport']
            if not host:
                host = self.host

            self.udp_transport = UdpServerConnection(host, port, key)

            self.send_mlat = self.udp_transport.send_mlat
            self.send_sync = self.udp_transport.send_sync
            self.send_split_sync = self.udp_transport.send_split_sync
        else:
            self.udp_transport = None
            self.send_mlat = self.send_tcp_mlat
            self.send_sync = self.send_tcp_sync
            self.send_split_sync = self.send_tcp_split_sync

        # turn off the sync method we don't want
        if response.get('split_sync', False):
            self.send_sync = None
        else:
            self.send_split_sync = None

        log('Handshake complete.')
        log('  Compression:       {0}', compress)
        log('  UDP transport:     {0}', self.udp_transport and str(self.udp_transport) or 'disabled')
        log('  Split sync:        {0}', self.send_split_sync and 'enabled' or 'disabled')

        self.state = 'ready'
        self.handle_server_line = self.handle_connected_request
        self.coordinator.server_connected()

        # dummy rate report to indicate we'll be sending them
        self.send_rate_report({})
示例#55
0
 def _send_json(self, o):
     if DEBUG:
         log('Send: {0}', o)
     self.linebuf.append(json.dumps(o, separators=(',', ':')))
示例#56
0
 def log_info(self, message, type='info'):
     log('{0}: {1}', message, type)
示例#57
0
 def log(self, fmt, *args, **kwargs):
     log('{what} with {addr[0]}:{addr[1]}: ' + fmt, *args, what=self.describe(), addr=self.addr, **kwargs)
示例#58
0
 def handle_close(self):
     log('Lost SBS output connection from {0}:{1}', self.addr[0], self.addr[1])
     self.close()
示例#59
0
 def log(self, fmt, *args, **kwargs):
     log('{what} with {host}:{port}: ' + fmt,
         *args,
         what=self.describe(), host=self.addr[0], port=self.addr[1],
         **kwargs)
示例#60
0
 def disconnect(self, reason):
     if self.state != 'disconnected':
         log('Disconnecting from {host}:{port}: {reason}', host=self.host, port=self.port, reason=reason)
         self.close(True)