Exemple #1
0
    def __init__(self, reader, writer, *, coordinator, motd, udp_protocol,
                 udp_host, udp_port):
        self.r = reader
        self.w = writer
        self.coordinator = coordinator
        self.loop = coordinator.loop
        self.motd = motd

        self.sync_accepted = 0
        self.sync_rejected = 0
        self.mc_start = time.time()
        self.mrate_limit = 80

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

        self.source_ip = peer[0]
        self.source_port = str(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._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 = zlib.compressobj(1)
        self._decompressor = zlib.decompressobj()
        self._pending_flush = None
        self._writebuf = []

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

        self.message_counter = 0
        self.return_stats = False

        # 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.time()
        self.heartbeat_task = asyncio.ensure_future(self.send_heartbeats())
        self.reader_task = asyncio.ensure_future(self.read_until_eof())

        self.logger.warning("Connection established")
        self.coordinator.add_output_handler(self.write_result)
    async def process_handshake(self):
        deny = None

        rawline = await asyncio.wait_for(self.r.readline(), timeout=15.0)
        try:
            line = rawline.decode('ascii')
            if line.startswith('PROXY '):
                proxyLine = line.split(' ')
                self.source_ip = proxyLine[2]
                self.source_port = proxyLine[4]
                rawline = await asyncio.wait_for(self.r.readline(), timeout=15.0)
                line = rawline.decode('ascii')

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

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

                user = str(hs['user'])
                uuid = hs.get('uuid')

                # 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) < 3:
                    user = user + '_' + str(random.randrange(10,99))

                if user in self.coordinator.usernames:
                    existingReceiver = self.coordinator.usernames[user]

                    if uuid and uuid == existingReceiver.uuid:
                        # if we have another user with the same uuid, disconnect the existing user
                        existingReceiver.connection.close()
                    else:
                        while user in self.coordinator.usernames:
                            user = user + '_' + str(random.randrange(10,99))


                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 = '{user} v{v} {clock_type} {cversion} {udp} {compress}'.format(
                    user=user,
                    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=uuid,
                                                              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(10),
                    "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("Handshake successful ({conn_info})".format(conn_info=conn_info))
        self.logger = util.TaggingLogger(glogger, {'tag': '{user}'.format(user=user)})
        return True