def __init__(self, reader, writer, *, coordinator, motd, udp_protocol,
                 udp_host, udp_port):
        self.r = reader
        self.w = writer
        self.coordinator = coordinator
        self.motd = motd

        self.message_counter = 0
        self.mc_start = time.monotonic()
        self.processed_counter = 0

        self.transport = writer.transport
        peer = self.transport.get_extra_info('peername')
        self.host = peer[0]
        self.port = peer[1]

        self.udp_protocol = udp_protocol
        self.udp_host = udp_host
        self.udp_port = udp_port

        self.logger = util.TaggingLogger(
            glogger,
            {'tag': '{host}:{port}'.format(host=self.host, port=self.port)})

        self.receiver = None

        self._read_task = None
        self._heartbeat_task = None
        self._pending_traffic_update = None
        self._pending_flush = None

        self._udp_key = None
        self._compression_methods = (('zlib2', self.handle_zlib_messages,
                                      self.write_zlib),
                                     ('zlib', self.handle_zlib_messages,
                                      self.write_raw),
                                     ('none', self.handle_line_messages,
                                      self.write_raw))
        self._last_message_time = None
        self._compressor = None
        self._pending_flush = None
        self._writebuf = []

        self._requested_traffic = set()
        self._wanted_traffic = set()

        # start
        self._read_task = asyncio.ensure_future(self.handle_connection())
Exemple #2
0
    def __init__(self,
                 reader,
                 writer,
                 *,
                 coordinator,
                 use_kalman_data,
                 heartbeat_interval=30.0):
        peer = writer.get_extra_info('peername')
        self.host = peer[0]
        self.port = peer[1]
        self.logger = util.TaggingLogger(
            logging.getLogger("basestation"),
            {'tag': '{host}:{port}'.format(host=self.host, port=self.port)})
        self.reader = reader
        self.writer = writer
        self.coordinator = coordinator
        self.use_kalman_data = use_kalman_data
        self.heartbeat_interval = heartbeat_interval
        self.last_output = time.monotonic()
        self.heartbeat_task = asyncio.ensure_future(self.send_heartbeats())
        self.reader_task = asyncio.ensure_future(self.read_until_eof())

        self.logger.info("Connection established")
        self.coordinator.add_output_handler(self.write_result)
    def process_handshake(self, line):
        deny = None

        try:
            hs = json.loads(line.decode('ascii'))
        except ValueError as e:
            deny = 'Badly formatted handshake: ' + str(e)
        else:
            try:
                self.coordinator.handshake_logger.debug(line.decode('ascii'))

                if hs['version'] != 2 and hs['version'] != 3:
                    raise ValueError('Unsupported version in handshake')

                user = str(hs['user'])

                # Newlines wreak havoc on log files, strip them
                user = re.sub("\n|\r", r'\\n', user)
                # replace bad characters with an underscore
                user = re.sub("[^A-Za-z0-9_.-]", r'_', user)
                if len(user) > 400:
                    user = user[:400]
                if len(user) < 5:
                    user = user + '_' + str(random.randrange(10000, 99999))
                # Make sure the user string is sane...
                good_user_regex = '^[A-Za-z0-9_.-]+$'
                user_ok = re.match(good_user_regex, user)
                if user_ok is None:
                    raise ValueError(
                        "Bad username '{user}'.  Please only use alphanum, '_', '-', or '.'"
                        .format(user=user))

                for i in range(5):
                    if user in self.coordinator.receivers:
                        user = user + '_' + str(random.randrange(10, 99))
                    else:
                        break

                peer_compression_methods = set(hs['compress'])
                self.compress = None
                for c, readmeth, writemeth in self._compression_methods:
                    if c in peer_compression_methods:
                        self.compress = c
                        self.handle_messages = readmeth
                        self.send = writemeth
                        break
                if self.compress is None:
                    raise ValueError('No mutually usable compression type')

                lat = float(hs['lat'])
                if lat < -90 or lat > 90:
                    raise ValueError('invalid latitude, should be -90 .. 90')

                lon = float(hs['lon'])
                if lon < -180 or lon > 360:
                    raise ValueError(
                        'invalid longitude, should be -180 .. 360')
                if lon > 180:
                    lon = lon - 180

                alt = float(hs['alt'])
                if alt < -1000 or alt > 10000:
                    raise ValueError(
                        'invalid altitude, should be -1000 .. 10000')

                clock_type = str(hs.get('clock_type', 'dump1090'))

                self.use_return_results = bool(hs.get('return_results', False))
                if self.use_return_results:
                    return_result_format = hs.get('return_result_format',
                                                  'old')
                    if return_result_format == 'old':
                        self.report_mlat_position = self.report_mlat_position_old
                    elif return_result_format == 'ecef':
                        self.report_mlat_position = self.report_mlat_position_ecef
                    else:
                        raise ValueError(
                            'invalid return_result_format, should be one of "old" or "ecef"'
                        )
                else:
                    self.report_mlat_position = self.report_mlat_position_discard

                self.use_udp = (self.udp_protocol is not None
                                and hs.get('udp_transport', 0) == 2)

                conn_info = 'v{v} {clock_type} {cversion} {udp} {compress}'.format(
                    v=hs['version'],
                    cversion=hs.get("client_version", "unknown"),
                    udp="udp" if self.use_udp else "tcp",
                    clock_type=clock_type,
                    compress=self.compress)
                self.receiver = self.coordinator.new_receiver(
                    connection=self,
                    uuid=user,
                    user=user,
                    auth=hs.get('auth'),
                    clock_type=clock_type,
                    position_llh=(lat, lon, alt),
                    privacy=bool(hs.get('privacy', False)),
                    connection_info=conn_info)

                # disabled until I get to the bottom of the odd timestamps
                if False and self.receiver.clock.epoch == 'gps_midnight':
                    self.process_mlat = self.process_mlat_gps
                else:
                    self.process_mlat = self.process_mlat_nongps

            except KeyError as e:
                deny = 'Missing field in handshake: ' + str(e)

            except ValueError as e:
                deny = 'Bad values in handshake: ' + str(e)

        if deny:
            self.logger.warning('Handshake failed: %s', deny)
            self.write_raw(deny=[deny], reconnect_in=util.fuzzy(900))
            return False

        expanded_motd = """

        {motd}

        The multilateration server source code is available under
        the terms of the Affero GPL (v3 or later). You may obtain
        a copy of this server's source code at the following
        location: {agpl_url}
        """.format(agpl_url=config.AGPL_SERVER_CODE_URL, motd=self.motd)

        response = {
            "compress": self.compress,
            "reconnect_in": util.fuzzy(15),
            "selective_traffic": True,
            "heartbeat": True,
            "return_results": self.use_return_results,
            "rate_reports": True,
            "motd": expanded_motd
        }

        if self.use_udp:
            self._udp_key = self.udp_protocol.add_client(
                sync_handler=self.process_sync, mlat_handler=self.process_mlat)
            response['udp_transport'] = (self.udp_host, self.udp_port,
                                         self._udp_key)

        self.write_raw(**response)
        strange = ''
        if clock_type != 'dump1090' and clock_type != 'radarcape_gps':
            strange = 'strange clock: '
        self.logger.warning(
            "{strange}Handshake successful ({user} {conn_info})'".format(
                strange=strange, user=user, conn_info=conn_info))
        self.logger = util.TaggingLogger(glogger,
                                         {'tag': '{user}'.format(user=user)})
        return True
Exemple #4
0
    def process_handshake(self, line):
        deny = None

        try:
            hs = json.loads(line.decode('ascii'))
        except ValueError as e:
            deny = 'Badly formatted handshake: ' + str(e)
        else:
            try:
                if hs['version'] != 2 and hs['version'] != 3:
                    raise ValueError('Unsupported version in handshake')

                user = str(hs['user'])

                peer_compression_methods = set(hs['compress'])
                self.compress = None
                for c, readmeth, writemeth in self._compression_methods:
                    if c in peer_compression_methods:
                        self.compress = c
                        self.handle_messages = readmeth
                        self.send = writemeth
                        break
                if self.compress is None:
                    raise ValueError('No mutually usable compression type')

                lat = float(hs['lat'])
                if lat < -90 or lat > 90:
                    raise ValueError('invalid latitude, should be -90 .. 90')

                lon = float(hs['lon'])
                if lon < -180 or lon > 360:
                    raise ValueError(
                        'invalid longitude, should be -180 .. 360')
                if lon > 180:
                    lon = lon - 180

                alt = float(hs['alt'])
                if alt < -1000 or alt > 10000:
                    raise ValueError(
                        'invalid altitude, should be -1000 .. 10000')

                clock_type = str(hs.get('clock_type', 'dump1090'))

                self.use_return_results = bool(hs.get('return_results', False))
                if self.use_return_results:
                    return_result_format = hs.get('return_result_format',
                                                  'old')
                    if return_result_format == 'old':
                        self.report_mlat_position = self.report_mlat_position_old
                    elif return_result_format == 'ecef':
                        self.report_mlat_position = self.report_mlat_position_ecef
                    else:
                        raise ValueError(
                            'invalid return_result_format, should be one of "old" or "ecef"'
                        )
                else:
                    self.report_mlat_position = self.report_mlat_position_discard

                self.use_udp = (self.udp_protocol is not None
                                and hs.get('udp_transport', 0) == 2)

                conn_info = 'v{v} {clock_type} {cversion} {udp} {compress}'.format(
                    v=hs['version'],
                    cversion=hs.get("client_version", "unknown"),
                    udp="udp" if self.use_udp else "tcp",
                    clock_type=clock_type,
                    compress=self.compress)
                self.receiver = self.coordinator.new_receiver(
                    connection=self,
                    uuid=user,
                    user=user,
                    auth=hs.get('auth'),
                    clock_type=clock_type,
                    position_llh=(lat, lon, alt),
                    privacy=bool(hs.get('privacy', False)),
                    connection_info=conn_info)

                # disabled until I get to the bottom of the odd timestamps
                if False and self.receiver.clock.epoch == 'gps_midnight':
                    self.process_mlat = self.process_mlat_gps
                else:
                    self.process_mlat = self.process_mlat_nongps

            except KeyError as e:
                deny = 'Missing field in handshake: ' + str(e)

            except ValueError as e:
                deny = 'Bad values in handshake: ' + str(e)

        if deny:
            self.logger.info('Handshake failed: %s', deny)
            self.write_raw(deny=[deny], reconnect_in=util.fuzzy(900))
            return False

        expanded_motd = """

        {motd}

        The multilateration server source code is available under
        the terms of the Affero GPL (v3 or later). You may obtain
        a copy of this server's source code at the following
        location: {agpl_url}
        """.format(agpl_url=config.AGPL_SERVER_CODE_URL, motd=self.motd)

        response = {
            "compress": self.compress,
            "reconnect_in": util.fuzzy(15),
            "selective_traffic": True,
            "heartbeat": True,
            "return_results": self.use_return_results,
            "rate_reports": True,
            "motd": expanded_motd
        }

        if self.use_udp:
            self._udp_key = self.udp_protocol.add_client(
                sync_handler=self.process_sync, mlat_handler=self.process_mlat)
            response['udp_transport'] = (self.udp_host, self.udp_port,
                                         self._udp_key)

        self.write_raw(**response)
        self.logger.info("Handshake successful ({user} {conn_info})'".format(
            user=user, conn_info=conn_info))
        self.logger = util.TaggingLogger(glogger,
                                         {'tag': '{user}'.format(user=user)})
        return True