示例#1
0
    def __init__(self, config: NetworkConfig, l3_protocol: L3Protocol,
                 scheduler: Scheduler):
        self.config = config
        self.sm = NetRomStateMachine(self, scheduler.timer)
        # Mapping of destination addresses to protocol factory. When a new connection is made to the destination
        # we will create a new instance of the protocol as well as a NetRom transport and add it to l3_connections
        self.l3_servers: Dict[AX25Call, Callable[[], Protocol]] = {}

        # This is a mapping of local circuit IDs to (transport, protocol). When incoming data is handled for a
        # circuit, this is how we pass it on to the instance of the protocol
        self.l3_connections: Dict[int, Tuple[Transport, Protocol]] = {}

        # This is a mapping of local circuit ID to a protocol factory. These protocols do not yet have a transport and
        # are in a half-opened state. Once a connect ack is received, a transport will be created and these will be
        # migrated to l3_connections
        self.l3_half_open: Dict[int, Protocol] = {}

        self.l3_destinations: Set[AX25Call] = set()

        self.l3_protocol = l3_protocol
        self.l3_protocol.register_transport_protocol(self)

        def extra():
            return f"[L4]"

        LoggingMixin.__init__(self, logging.getLogger("main"), extra)
    def __init__(self,
                 node_call: AX25Call,
                 node_alias: str,
                 scheduler: Scheduler,
                 link_multiplexer: LinkMultiplexer,
                 routing_table):
        LoggingMixin.__init__(self)
        self.node_call = node_call
        self.node_alias = node_alias
        self.link_multiplexer = link_multiplexer
        self.router = routing_table
        self.nodes_timer = scheduler.timer(60000.0, self.broadcast_nodes)
        self.netrom_transport = None
        self.nodes_lock = threading.Lock()

        # Register our-calls with routing table
        for l2 in link_multiplexer.l2_devices.values():
            l2_address = l2.get_link_address()
            if isinstance(l2_address, AX25Address):
                self.router.our_calls.add(cast(AX25Address, l2_address).to_ax25_call())

        now = datetime.datetime.now()
        prune_intervals = round((now - self.router.updated_at).seconds / 60.000)
        if prune_intervals < 10:
            self.info(f"Pruning routes {prune_intervals} times")
            for i in range(prune_intervals):
                self.router.prune_routes()
        else:
            self.info("Routes too old, discarding.")
            self.router.clear_routes()

        self.nodes_timer.start()
        self.broadcast_nodes()
示例#3
0
    def __init__(self, config: PortConfig, link_port: int, link_call: AX25Call,
                 scheduler: Scheduler, queue: L2Queuing,
                 link_multiplexer: DefaultLinkMultiplexer,
                 l3_protocols: L3Protocols, intercept_calls: Set[AX25Call],
                 interceptor: Callable[[FrameData], None]):
        self.config = config
        self.link_port = link_port
        self.link_call = link_call
        self.queue = queue  # l2 buffer
        self.link_multiplexer = link_multiplexer
        self.l3_protocols = l3_protocols
        self.intercept_calls = intercept_calls
        self.interceptor = interceptor

        # Mapping of link_id to AX25 address. When we establish new logical links,
        # add them here so we can properly address payloads from L3
        self.links_by_id: Dict[int, AX25Call] = dict()
        self.links_by_address: Dict[AX25Call, int] = dict()

        self.state_machine = AX25StateMachine(self, scheduler.timer)
        self.link_multiplexer.register_device(self)

        self.cq_timer = scheduler.timer(300_000, self._send_cq, True)
        scheduler.timer(5_000, self.state_machine.start, True)

        def extra():
            return f"[L2 AX25 Port={self.link_port} Call={str(self.link_call)}]"

        LoggingMixin.__init__(self, extra_func=extra)
示例#4
0
 def __init__(self, path: str, protocol: Protocol):
     CloseableThread.__init__(self, f"Unix Server {path}")
     LoggingMixin.__init__(self)
     self.path = path
     self.protocol = protocol
     self.server: Optional[Server] = None
     self._loop: Optional[AbstractEventLoop] = None
示例#5
0
    def __init__(self, config: NetworkConfig, loop: AbstractEventLoop):
        self.config = config
        self.sm = NetRomStateMachine(self, AsyncioTimer)
        self.router = NetRomRoutingTable(config.node_alias())
        self.l3_apps: Dict[AX25Call, str] = {}

        # Mapping of destination addresses to protocol factory. When a new connection is made to the destination
        # we will create a new instance of the protocol as well as a NetRom transport and add it to l3_connections
        self.l3_servers: Dict[AX25Call, Callable[[], Protocol]] = {}

        # This is a mapping of local circuit IDs to (transport, protocol). When incoming data is handled for a
        # circuit, this is how we pass it on to the instance of the protocol
        self.l3_connections: Dict[int, Tuple[Transport, Protocol]] = {}

        # This is a mapping of local circuit ID to a protocol factory. These protocols do not yet have a transport and
        # are in a half-opened state. Once a connect ack is received, a transport will be created and these will be
        # migrated to l3_connections
        self.l3_half_open: Dict[int, Callable[[], Protocol]] = {}

        self.data_links: Dict[int, DataLinkManager] = {}
        self.route_lock = Lock()
        self.loop = loop

        def extra():
            return f"[L4 Call={str(config.node_call())} Alias={config.node_alias()}]"

        LoggingMixin.__init__(self, logging.getLogger("main"), extra)
示例#6
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     LoggingMixin.__init__(self,
                           logger=logging.getLogger("serial"),
                           extra_func=partial(str, f"[Serial Writer {self.ser.name}]"))
     self.unsent = deque(maxlen=20)
     self.retry_backoff = BackoffGenerator(0.100, 1.2, 1.000)
示例#7
0
 def __init__(self, queue: L3Queueing, l2: L2Protocol):
     CloseableThreadLoop.__init__(
         self, name=f"L3-to-L2 for Port={l2.get_device_id()}")
     LoggingMixin.__init__(self)
     self.queue = queue
     self.l2 = l2
     self.retry_backoff = BackoffGenerator(0.500, 1.5, 3.000)
示例#8
0
    def __init__(self, protocol: IOProtocol, device_name: str, speed: int,
                 timeout: float, scheduler: Scheduler):
        LoggingMixin.__init__(self)
        CloseableThreadLoop.__init__(self, f"Serial Device {device_name}")

        self._scheduler = scheduler
        self._device_name = device_name
        self._protocol = protocol
        self._ser = serial.Serial(port=None,
                                  baudrate=speed,
                                  timeout=timeout,
                                  write_timeout=timeout)
        self._ser.port = device_name
        self._closed_latch = CountDownLatch(2)
        self._open_event = threading.Event()
        self._error_event = threading.Event()
        self._open_backoff = BackoffGenerator(0.100, 1.2, 5.000)
        # Submit the reader and writer threads first, so they will be shutdown first
        self._scheduler.submit(
            SerialReadLoop(f"Serial Reader {self._ser.name}", self._ser,
                           self._protocol, self._open_event, self._error_event,
                           self._closed_latch))
        self._scheduler.submit(
            SerialWriteLoop(f"Serial Writer {self._ser.name}", self._ser,
                            self._protocol, self._open_event,
                            self._error_event, self._closed_latch))
        self._scheduler.submit(self)
示例#9
0
 def __init__(self, network_app: NetworkApp, environ: Dict[str, Any]):
     LoggingMixin.__init__(self)
     self.environ = environ
     self.network_app = network_app
     self.transport = None
     self.closed = False
     self.unpacker = msgpack.Unpacker()
示例#10
0
 def __init__(self, l3_protocol: L3Protocol):
     LoggingMixin.__init__(self)
     self.l3_protocol = l3_protocol
     self.connections: Dict[int, Tuple[Transport, DProtocol]] = dict()
     self.l3_protocol.register_transport_protocol(self)
     self.broadcast_protocol: Optional[BroadcastProtocol] = None
     self.datagram_protocol: Optional[DatagramProtocol] = None
示例#11
0
 def __init__(self, network: L3Protocol, datagram_manager: L4Protocol,
              fragment_protocol: FragmentProtocol,
              reliable_protocol: ReliableProtocol):
     LoggingMixin.__init__(self)
     self.network = network
     self.datagram_manager = datagram_manager
     self.fragment_protocol = fragment_protocol
     self.reliable_protocol = reliable_protocol
示例#12
0
    def __init__(self, network: L3Protocol, datagram_manager: L4Protocol):
        LoggingMixin.__init__(self)
        self.network = network
        self.datagram_manager = datagram_manager

        self.send_seq: int = 1
        self.seq_lock = threading.Lock()

        # A buffer of undelivered fragment. Structured like source -> sequence -> fragments
        self.buffer: Dict[MeshAddress, Dict[
            int, List[Fragment]]] = defaultdict(lambda: defaultdict(list))
示例#13
0
    def __init__(self, network: MeshProtocol, transport: L4Protocol,
                 reliable_manager: ReliableManager):
        LoggingMixin.__init__(self)
        self.network = network
        self.transport = transport
        self.reliable_manager = reliable_manager

        self.send_seq: int = 1
        self.seq_lock = threading.Lock()

        self.ttl_cache = TTLCache(WallTime(), 30_000)
示例#14
0
 def __init__(self, host: str, port: int, port_mapping: Dict[AX25Call, int],
              port_queues: Dict[int, L2Queuing], writer: UDPWriter):
     CloseableThread.__init__(self, f"UDP {host}:{port}")
     LoggingMixin.__init__(self, udp_logger)
     self.host = host
     self.port = port
     self.port_mapping = port_mapping
     self.port_queues = port_queues
     self.writer = writer
     self._loop: Optional[AbstractEventLoop] = None
     self._transport = None
示例#15
0
 def __init__(self, app_name: str, app_call: AX25Call, app_alias: str,
              transport_manager: NetRomTransportProtocol,
              multiplexer: TransportMultiplexer):
     Protocol.__init__(self)
     LoggingMixin.__init__(self)
     self.app_name = app_name
     self.app_call = app_call
     self.app_alias = app_alias
     self.transport_manager = transport_manager
     self.multiplexer = multiplexer
     self.unpacker = msgpack.Unpacker()
     self.out_queue = queue.Queue()
示例#16
0
 def __init__(self, app_name: str, app_alias: str, app_bind_address: str,
              transport_manager: L4Protocol,
              multiplexer: TransportMultiplexer):
     Protocol.__init__(self)
     LoggingMixin.__init__(self)
     self.app_name = app_name
     self.app_alias = app_alias
     self.app_bind_address = app_bind_address
     self.transport_manager = transport_manager
     self.multiplexer = multiplexer
     self.unpacker = msgpack.Unpacker()
     self.out_queue = queue.Queue()
示例#17
0
    def __init__(self, queue_size, max_payload_size):
        LoggingMixin.__init__(self)
        self._max_payload_size = max_payload_size
        self._outbound = queue.Queue(maxsize=queue_size)

        # Ring buffer for decoded inbound messages
        self._inbound = deque(maxlen=queue_size)
        self._inbound_count = itertools.count()
        self._last_inbound = next(self._inbound_count)

        self._lock: threading.Lock = threading.Lock()
        self._not_empty: threading.Condition = threading.Condition(self._lock)
示例#18
0
    def __init__(self, config: NetworkConfig, link: LinkMultiplexer,
                 network: MeshProtocol,
                 transport_manager: MeshTransportManager,
                 scheduler: Scheduler):
        self.config = config
        self.l3 = network
        self.l2s = link
        self.l4 = transport_manager
        self.scheduler = scheduler
        self.transport: Optional[Transport] = None
        self.client_transport: Optional[Transport] = None
        self.pending_open: Optional[AX25Call] = None

        self.parser = argparse.ArgumentParser(prog="TARPN", add_help=False)
        sub_parsers = self.parser.add_subparsers(title="command",
                                                 required=True,
                                                 dest="command")

        sub_parsers.add_parser("help", description="Print this help")
        sub_parsers.add_parser("bye", description="Disconnect from this node")
        sub_parsers.add_parser("whoami", description="Print the current user")
        sub_parsers.add_parser("hostname",
                               description="Print the current host")
        sub_parsers.add_parser("routes",
                               description="Print the current routing table")
        sub_parsers.add_parser(
            "nodes", description="Print the nodes in the routing table")

        port_parser = sub_parsers.add_parser(
            "ports", description="List available ports")
        port_parser.add_argument("--verbose", "-v", action="store_true")

        link_parser = sub_parsers.add_parser("links",
                                             description="Show existing links")
        link_parser.add_argument("--verbose", "-v", action="store_true")

        connect_parser = sub_parsers.add_parser(
            "connect", description="Connect to a remote station")
        connect_parser.add_argument("dest",
                                    type=str,
                                    help="Destination callsign to connect to")

        def extra():
            if self.transport:
                (host, port) = self.transport.get_extra_info('peername')
                return f"[Admin {host}:{port}]"
            else:
                return ""

        LoggingMixin.__init__(self, extra_func=extra)
        self.info("Created NodeCommandProcessor")
示例#19
0
    def __init__(self, network: MeshProtocol, scheduler: Scheduler):
        LoggingMixin.__init__(self)
        self.network = network
        self.scheduler = scheduler

        self.mutex = threading.Lock()
        self.not_empty = threading.Condition(self.mutex)
        self.not_full = threading.Condition(self.mutex)

        self.sent: deque[ReliableItem] = deque()
        self.timer = scheduler.timer(3_000, self.check_acks)
        self.backoff = backoff(1_000, 1.2, 5_000)

        self.seq_by_neighbor: Dict[MeshAddress, int] = defaultdict(int)
示例#20
0
    def __init__(self, link_call: AX25Call, link_port: int,
                 inbound: asyncio.Queue, outbound: asyncio.Queue,
                 future_provider: Callable[[], Future]):
        self.link_call = link_call
        self.link_port = link_port
        self.inbound = inbound  # PortFrame
        self.outbound = outbound  # PortFrame
        self.state_machine = AX25StateMachine(self, AsyncioTimer)
        self.l3_handlers: List[L3Handler] = []
        self.future_provider = future_provider
        self._stopped: bool = False

        def extra():
            return f"[L2 Port={self.link_port} Call={str(self.link_call)}]"

        LoggingMixin.__init__(self, logging.getLogger("main"), extra)
示例#21
0
    def __init__(self, time: Time, config: NetworkConfig,
                 link_multiplexer: LinkMultiplexer, l4_handlers: L4Handlers,
                 scheduler: Scheduler):
        LoggingMixin.__init__(self, extra_func=self.log_ident)
        CloseableThreadLoop.__init__(self, name="MeshNetwork")

        self.time = time
        self.config = config
        self.link_multiplexer = link_multiplexer
        self.l4_handlers = l4_handlers
        self.scheduler = scheduler

        self.queue = queue.Queue()
        self.our_address = MeshAddress.parse(config.get("mesh.address"))
        self.host_name = config.get("host.name")
        self.ping_protocol = PingProtocol(self)

        # TTL cache of seen frames from each source
        self.header_cache: TTLCache = TTLCache(time, 30_000)

        # Our own send sequence
        self.send_seq: int = 1
        self.seq_lock = threading.Lock()

        # Link states and neighbors
        self.neighbors: Dict[MeshAddress, Neighbor] = dict()

        # An epoch for our own link state changes. Any time a neighbor comes or goes, or the quality changes,
        # we increment this counter. Uses a "lollipop sequence" to allow for easy detection of wrap around vs
        # reset
        self.our_link_state_epoch_generator = lollipop_sequence()
        self.our_link_state_epoch: int = next(
            self.our_link_state_epoch_generator)

        # Epochs we have received from other nodes and their link states
        self.link_state_epochs: Dict[MeshAddress, int] = dict()
        self.host_names: Dict[MeshAddress, str] = dict()
        self.link_states: Dict[MeshAddress, List[LinkStateHeader]] = dict()

        self.last_hello_time = datetime.fromtimestamp(0)
        self.last_advert = datetime.utcnow()
        self.last_query = datetime.utcnow()
        self.last_epoch_bump = datetime.utcnow()

        self.scheduler.timer(1_000, partial(self.scheduler.submit, self), True)
示例#22
0
    def __init__(self, settings: Settings, links: List[DataLinkManager],
                 network: NetRom):
        self.settings: Settings = settings
        self.transport: Optional[Transport] = None
        self.client_transport: Optional[NetworkTransport] = None
        self.datalinks: List[DataLinkManager] = links
        self.network: NetRom = network
        self.pending_open: Optional[AX25Call] = None

        parser = argparse.ArgumentParser(prog="TARPN", add_help=False)
        sub_parsers = parser.add_subparsers(title="command",
                                            required=True,
                                            dest="command")

        sub_parsers.add_parser("help", description="Print this help")
        sub_parsers.add_parser("bye", description="Disconnect from this node")
        sub_parsers.add_parser("whoami", description="Print the current user")
        sub_parsers.add_parser("hostname",
                               description="Print the current host")

        port_parser = sub_parsers.add_parser(
            "ports", description="List available ports")
        port_parser.add_argument("--verbose", "-v", action="store_true")

        link_parser = sub_parsers.add_parser("links",
                                             description="Show existing links")
        link_parser.add_argument("--verbose", "-v", action="store_true")

        connect_parser = sub_parsers.add_parser(
            "connect", description="Connect to a remote station")
        connect_parser.add_argument("dest",
                                    type=str,
                                    help="Destination callsign to connect to")

        self.parser = parser

        def extra():
            if self.transport:
                (host, port) = self.transport.get_extra_info('peername')
                return f"[Admin {host}:{port}]"
            else:
                return ""

        LoggingMixin.__init__(self, logging.getLogger("main"), extra)
        self.info("Created CommandProcessorProtocol")
示例#23
0
    def __init__(self,
                 port_id: int,
                 queue: L2IOQueuing,
                 check_crc: bool = False,
                 hdlc_port: int = 0):
        self.port_id = port_id
        self.check_crc = check_crc
        self.hdlc_port = hdlc_port

        self.msgs_recvd = 0
        self.in_frame = False
        self.saw_fend = False

        self._l2_queue: L2IOQueuing = queue
        self._send_immediate: Optional[bytes] = None
        self._buffer = bytearray()

        self.closed = False
        LoggingMixin.__init__(self, logging.getLogger("main"))
示例#24
0
    def __init__(self, link_port: int, link_call: AX25Call,
                 scheduler: Scheduler, queue: L2Queuing,
                 link_multiplexer: LinkMultiplexer, l3_protocols: L3Protocols):
        self.link_port = link_port
        self.link_call = link_call
        self.queue = queue  # l2 buffer
        self.link_multiplexer = link_multiplexer
        self.l3_protocols = l3_protocols

        # Mapping of link_id to AX25 address. When we establish new logical links,
        # add them here so we can properly address payloads from L3
        self.links_by_id: Dict[int, AX25Call] = dict()
        self.links_by_address: Dict[AX25Call, int] = dict()

        self.state_machine = AX25StateMachine(self, scheduler.timer)
        self.link_multiplexer.register_device(self)

        def extra():
            return f"[L2 AX25 Port={self.link_port} Call={str(self.link_call)}]"

        LoggingMixin.__init__(self, logging.getLogger("main"), extra)
示例#25
0
 def __init__(self):
     LoggingMixin.__init__(self)
     self.protocols: List[L3Protocol] = []
示例#26
0
 def __init__(self):
     LoggingMixin.__init__(self, logger=logging.getLogger("app"))
     self.socket_transport: Optional[Transport] = None
     self.network_transports: Dict[str, DTransport] = dict()
示例#27
0
 def __init__(self, environ):
     NetworkApp.__init__(self, environ)
     LoggingMixin.__init__(self)
     self.context = None
示例#28
0
 def __init__(self):
     LoggingMixin.__init__(self)
     self.handlers: Dict[Protocol, L4Handler] = dict()
示例#29
0
 def __init__(self, environ):
     NetworkApp.__init__(self, environ)
     LoggingMixin.__init__(self)
     self.context = None
     self.info(f"Created with {environ}")
示例#30
0
 def __init__(self):
     self.executor = ThreadPoolExecutor()
     self.threads: List[CloseableThread] = list()
     self.shutdown_tasks: List[Callable[..., Any]] = list()
     self._futures: List[Future] = list()
     LoggingMixin.__init__(self)