Ejemplo n.º 1
0
 def handle_l2_payload(self, payload: L2Payload):
     if payload.destination == AX25Address.from_ax25_call(AX25Call("ID")):
         print(f"Got ID from {payload.source}: {payload.l3_data}")
     elif payload.destination == AX25Address.from_ax25_call(AX25Call("CQ")):
         print(f"Got CQ from {payload.source}: {payload.l3_data}")
     else:
         print(f"Unhandled NoLayer3 payload {payload}, dropping.")
Ejemplo n.º 2
0
    def setUp(self):
        loop = asyncio.get_event_loop()
        in_queue_1 = asyncio.Queue()
        out_queue_1 = asyncio.Queue()
        protocol_factory = partial(KISSProtocol,
                                   loop,
                                   in_queue_1,
                                   out_queue_1,
                                   port_id=1,
                                   check_crc=False)
        (transport_1,
         protocol_1) = utils.create_test_connection(loop, protocol_factory)

        self.dlm_1 = DataLinkManager(AX25Call("K4DBZ", 1), 1, in_queue_1,
                                     out_queue_1, loop.create_future)
        self.nl_1 = NetworkManager(
            NetworkConfig.from_dict({
                "netrom.node.call": "K4DBZ-1",
                "netrom.node.alias": "NODE1",
                "netrom.nodes.interval": 10
            }), loop)
        self.nl_1.attach_data_link(self.dlm_1)

        self.transport_1 = cast(utils.TestTransport, transport_1)
        self.protocol_1 = cast(KISSProtocol, protocol_1)

        in_queue_2 = asyncio.Queue()
        out_queue_2 = asyncio.Queue()
        protocol_factory = partial(KISSProtocol,
                                   loop,
                                   in_queue_2,
                                   out_queue_2,
                                   port_id=2,
                                   check_crc=False)
        (transport_2,
         protocol_2) = utils.create_test_connection(loop, protocol_factory)

        self.dlm_2 = DataLinkManager(AX25Call("K4DBZ", 2), 2, in_queue_2,
                                     out_queue_2, loop.create_future)
        self.nl_2 = NetworkManager(
            NetworkConfig.from_dict({
                "netrom.node.call": "K4DBZ-2",
                "netrom.node.alias": "NODE2",
                "netrom.nodes.interval": 10
            }), loop)
        self.nl_2.attach_data_link(self.dlm_2)

        self.transport_2 = cast(utils.TestTransport, transport_2)
        self.protocol_2 = cast(KISSProtocol, protocol_2)

        logger = logging.getLogger("main")
        logger.setLevel(logging.INFO)
        handler = logging.StreamHandler(sys.stdout)
        handler.setFormatter(
            logging.Formatter('%(levelname)-8s %(asctime)s -- %(message)s'))
        handler.setLevel(logging.INFO)
        logger.addHandler(handler)
Ejemplo n.º 3
0
 def maybe_handle_special(self, port: int, packet: AX25Packet) -> bool:
     if packet.dest == AX25Call("ID") and isinstance(packet, UIFrame):
         ui = cast(UIFrame, packet)
         print(f"Got ID from {packet.source}: {ui.info}")
         return False
     elif packet.dest == AX25Call("CQ") and isinstance(packet, UIFrame):
         ui = cast(UIFrame, packet)
         print(f"Got CQ from {packet.source}: {ui.info}")
         return False
     return True
Ejemplo n.º 4
0
 def write(self, address, data):
     payload = AppPayload(0, 1, bytearray())
     ax25_address = AX25Call.parse(address)
     ax25_address.write(payload.buffer)
     payload.buffer.extend(data)
     msg = msgpack.packb(dataclasses.asdict(payload))
     self.transport.write(msg)
Ejemplo n.º 5
0
 async def _broadcast_nodes(self):
     nodes = self.router.get_nodes()
     nodes.save("nodes.json")
     for dl in self.data_links.values():
         for nodes_packet in nodes.to_packets(
                 AX25Call.parse(self.config.node_call())):
             dl.write_packet(nodes_packet)
Ejemplo n.º 6
0
    def receive_frame(self, frame: FrameData):
        try:
            ax25_packet = decode_ax25_packet(frame.data)

            intercepted = ax25_packet.dest in self.intercept_calls
            if intercepted:
                log_prefix = f"[Port={self.link_port} UDP]"
            else:
                log_prefix = f"[Port={self.link_port}]"
            if ax25_packet.dest == AX25Call("NODES"):
                packet_logger.debug(
                    f"{log_prefix} RX {len(ax25_packet.buffer)}: {ax25_packet}"
                )
            else:
                packet_logger.info(
                    f"{log_prefix} RX {len(ax25_packet.buffer)}: {ax25_packet}"
                )

            # Check for port forwarding
            if intercepted:
                self.interceptor(frame)
                return

            self.maybe_open_link(AX25Address.from_ax25_call(
                ax25_packet.source))
        except Exception:
            self.exception(f"Had error parsing packet: {frame}")
            return

        try:
            self.state_machine.handle_packet(ax25_packet)
        except Exception:
            self.state_machine.reset_state(ax25_packet.source)
            self.exception(f"Had error handling packet {ax25_packet}")
Ejemplo n.º 7
0
 def load(cls, file: str):
     if not os.path.exists(file):
         return None, 0
     with open(file) as fp:
         nodes_json = json.load(fp)
         sending_alias = nodes_json["nodeAlias"]
         destinations = []
         for dest_json in nodes_json["destinations"]:
             destinations.append(
                 NodeDestination(AX25Call.parse(dest_json["nodeCall"]),
                                 dest_json["nodeAlias"],
                                 AX25Call.parse(dest_json["bestNeighbor"]),
                                 int(dest_json["quality"])))
         return cls(sending_alias,
                    destinations), datetime.datetime.fromisoformat(
                        nodes_json["createdAt"])
Ejemplo n.º 8
0
 def to_packets(self, source: AX25Call) -> Iterator[UIFrame]:
     for dest_chunk in chunks(self.destinations, 11):
         nodes_chunk = NetRomNodes(self.sending_alias, dest_chunk)
         yield UIFrame.ui_frame(AX25Call("NODES", 0), source, [],
                                SupervisoryCommand.Command, False,
                                L3Protocol.NetRom,
                                encode_netrom_nodes(nodes_chunk))
Ejemplo n.º 9
0
    def _loop_sync(self, frame: FrameData):
        try:
            packet = decode_ax25_packet(frame.data)
            if packet.dest == AX25Call("NODES"):
                self.debug(f"RX: {packet}")
            else:
                self.debug(f"RX: {packet}")
            packet_logger.info(f"RX: {packet}")
            EventBus.emit("packet", [packet])
        except Exception:
            self.error(f"Had an error parsing packet: {frame}")
            return

        try:
            # Check if this is a special L3 message
            should_continue = True
            for l3 in self.l3_handlers:
                should_continue = l3.maybe_handle_special(frame.port, packet)
                if not should_continue:
                    self.debug(f"Handled by L3 {l3}")
                    break

            # If it has not been handled by L3
            if should_continue:
                if not packet.dest == self.link_call:
                    self.warning(
                        f"Discarding packet not for us {packet}. We are {self.link_call}"
                    )
                else:
                    self.state_machine.handle_packet(packet)
            else:
                self.debug(
                    "Not continuing because this packet was handled by L3")
        except Exception:
            self.error(f"Had handling packet {packet}")
Ejemplo n.º 10
0
 def route1(self, destination: L3Address) -> Optional[int]:
     if not isinstance(destination, l3.NetRomAddress):
         logger.warning(
             f"Wrong address family, expected NET/ROM got {destination.__class__}"
         )
         return None
     netrom_dest = cast(l3.NetRomAddress, destination)
     packet_dest = AX25Call(netrom_dest.callsign, netrom_dest.ssid)
     # TODO handle alias here
     if packet_dest in self.neighbors:
         logger.debug(f"Routing to neighbor {packet_dest}")
         return self.neighbors.get(str(packet_dest)).port
     else:
         dest = self.destinations.get(str(packet_dest))
         if dest:
             neighbors = dest.sorted_neighbors()
             logger.debug(f"Sorted neighbors: {neighbors}")
             if len(neighbors) > 0:
                 neighbor = self.neighbors.get(str(neighbors[0].neighbor))
                 if neighbor is not None:
                     return neighbor.port
                 else:
                     logger.warning(
                         f"Warning! Routed to dest {packet_dest} via {neighbors[0].neighbor}, "
                         f"but we have no entry for that neighbor!")
             else:
                 return None
         else:
             return None
Ejemplo n.º 11
0
 def write_packet(self, packet: AX25Packet):
     frame = FrameData(self.link_port, packet.buffer)
     if packet.dest == AX25Call("NODES"):
         packet_logger.debug(f"TX: {packet}")
     else:
         packet_logger.info(f"TX: {packet}")
     if not self.queue.offer_outbound(frame):
         self.warning("Could not send frame, buffer full")
Ejemplo n.º 12
0
 def write_packet(self, packet: AX25Packet):
     if packet.dest == AX25Call("NODES"):
         self.debug(f"TX: {packet}")
     else:
         self.debug(f"TX: {packet}")
     packet_logger.info(f"TX: {packet}")
     frame = FrameData(self.link_port, packet.buffer)
     asyncio.create_task(self.outbound.put(frame))
Ejemplo n.º 13
0
 def __init__(self, local_call: str, remote_call: str,
              datalink: DataLinkManager):
     self.local_call = AX25Call.parse(local_call)
     self.remote_call = AX25Call.parse(remote_call)
     self.dl = datalink
     self.stdin_queue = Queue()
     self.connected = False
     self.circuit_id = None
     EventBus.bind(
         EventListener(f"link.{local_call}.connect",
                       f"link_{local_call}_connect", self.handle_connect))
     EventBus.bind(
         EventListener(f"link.{local_call}.disconnect",
                       f"link_{local_call}_disconnect",
                       self.handle_disconnect))
     EventBus.bind(
         EventListener(f"link.{local_call}.inbound",
                       f"link_{local_call}_inbound", self.handle_data))
Ejemplo n.º 14
0
 def load(cls, filename: str, node_alias: str):
     if not os.path.exists(filename):
         return NetRomRoutingTable(node_alias=node_alias, updated_at=datetime.datetime.now())
     d = json_load(filename)
     return NetRomRoutingTable(node_alias=d["node_alias"],
                               updated_at=datetime.datetime.fromisoformat(d["updated_at"]),
                               our_calls={AX25Call.parse(call) for call in d["our_calls"]},
                               neighbors={n_dict["call"]: Neighbor.from_safe_dict(n_dict) for n_dict in d["neighbors"]},
                               destinations={d_dict["call"]: Destination.from_safe_dict(d_dict) for d_dict in d["destinations"]})
Ejemplo n.º 15
0
 def from_safe_dict(cls, d):
     instance = cls(node_call=AX25Call.parse(d["call"]),
                    node_alias=d["alias"],
                    freeze=d["freeze"])
     instance.neighbor_map = {
         route_dict["neighbor"]: Route.from_safe_dict(route_dict)
         for route_dict in d["routes"]
     }
     return instance
Ejemplo n.º 16
0
 def __init__(self, my_call: str, my_alias: str, remote_call, nl: NetRom):
     self.local_call = AX25Call.parse(my_call)
     self.local_alias = AX25Call(callsign=my_alias)
     self.remote_call = AX25Call.parse(remote_call)
     self.nl = nl
     self.stdin_queue = Queue()
     self.connected = False
     self.circuit_id = None
     EventBus.bind(
         EventListener(f"netrom.{my_call}.connect",
                       f"netrom_{my_call}_connect", self.handle_connect))
     EventBus.bind(
         EventListener(f"netrom.{my_call}.disconnect",
                       f"netrom_{my_call}_disconnect",
                       self.handle_disconnect))
     EventBus.bind(
         EventListener(f"netrom.{my_call}.inbound",
                       f"netrom_{my_call}_inbound", self.handle_data))
Ejemplo n.º 17
0
 def send_nodes_to_link(self, nodes: NetRomNodes, l2: L2Protocol):
     # not thread safe
     if isinstance(l2, AX25Protocol):
         # Special NET/ROM + AX.25 behavior
         for chunk in nodes.to_chunks():
             link_id = l2.maybe_create_logical_link(AX25Call("NODES"))
             payload = L3Payload(L3Address(), L3Address(), 0xCF, chunk, link_id, QoS.Lowest, reliable=False)
             packet_logger.debug(f"TX: {payload}")
             self.link_multiplexer.get_queue(link_id).offer(payload)
Ejemplo n.º 18
0
    async def wait_for_network():
        tty = TTY()
        loop.add_reader(sys.stdin, tty.handle_stdin)
        loop.add_signal_handler(signal.SIGTERM, tty.handle_signal, loop, scheduler)
        loop.add_signal_handler(signal.SIGINT, tty.handle_signal, loop, scheduler)

        remote_call = AX25Call.parse(args.remote_call)
        while True:
            (found, mtu) = netrom_l3.route_packet(NetRomAddress.from_call(remote_call))
            if found:
                break
            await asyncio.sleep(0.200)
        main_logger.info(f"Learned route to {remote_call}")
        await asyncio.sleep(1.200)
        netrom_l4.open(protocol_factory=lambda: tty,
                       local_call=AX25Call.parse(args.local_call),
                       remote_call=AX25Call.parse(args.remote_call),
                       origin_user=AX25Call(args.local_alias),
                       origin_node=AX25Call(args.local_call))
Ejemplo n.º 19
0
    def test_nodes(self):
        nodes_payload = b'\xffDAVID \x9cf\x98\xa8\xac@\x04DOUG  \x96\x9ch\x9e\xa4\x84dz\xaeh\x8a\x92\xa0@dDAVE  \x96' \
                        b'\x9ch\x9e\xa4\x84d_\x96\x9ah\x8a\xa0@\x04JAY   \x96\x9ch\x9e\xa4\x84dz\x96\xaeh\x96\xb4@dA' \
                        b'NOIA \x96\x9ch\x9e\xa4\x84d_\x96\x82d\x88\x8a\xaefFFVC  \x96\x9ch\x9e\xa4\x84dz\x96h\x8c' \
                        b'\x88@@dDAN   \x96\x9ch\x9e\xa4\x84d_\x96\x9ah\x92\x8c\xaa\x04ERECH \x96\x9ch\x9e\xa4\x84d' \
                        b'\x9c\x96h\x92\xa0\x9e@\x04GREG  \x96\x9ch\x9e\xa4\x84d_'
        nodes = parse_netrom_nodes(nodes_payload)
        assert nodes.sending_alias == "DAVID"

        re_encoded = encode_netrom_nodes(nodes)
        assert re_encoded == nodes_payload

        table = NetRomRoutingTable("DAVID")
        table.update_routes(AX25Call("K4DBZ", 2), 0, nodes)
        print(table)

        routes = table.route(NetRomInfo(AX25Call("K4DBZ", 2), AX25Call("N3LTV", 2), 0, 0, 0, 0, 0, OpType.Information,
                                        "Hello, Doug".encode("ascii")))
        print(routes)
        print(table.get_nodes())
Ejemplo n.º 20
0
    async def _handle_packet_async(self, netrom_packet: NetRomPacket):
        """If packet is for us, handle it, otherwise forward it using our L3 routing table"""

        EventBus.emit("netrom.incoming", [netrom_packet])
        self.debug(f"RX: {netrom_packet}")
        packet_logger.info(f"RX: {netrom_packet}")

        if netrom_packet.dest == AX25Call("KEEPLI-0"):
            # What are these?? Just ignore them
            pass
        elif netrom_packet.dest == AX25Call.parse(self.config.node_call()):
            # Destination is this node
            self.sm.handle_packet(netrom_packet)
        elif netrom_packet.dest in self.l3_apps:
            # Destination is an app served by this node
            self.sm.handle_packet(netrom_packet)
        elif netrom_packet.dest in self.l3_servers:
            # Destination is an app served by this node
            self.sm.handle_packet(netrom_packet)
        else:
            # Destination is somewhere else
            self.write_packet(netrom_packet, forward=True)
Ejemplo n.º 21
0
 def maybe_handle_special(self, port: int, packet: AX25Packet) -> bool:
     """L3Handler.maybe_handle_special"""
     if type(packet) == UIFrame:
         ui = cast(UIFrame, packet)
         if ui.protocol == L3Protocol.NetRom and ui.dest == AX25Call(
                 "NODES"):
             # Parse this NODES packet and mark it as handled
             nodes = parse_netrom_nodes(ui.info)
             EventBus.emit("netrom.nodes", [nodes])
             asyncio.get_event_loop().create_task(
                 self._update_nodes(packet.source, port, nodes))
             # Stop further processing
             return False
     return True
Ejemplo n.º 22
0
 def route1(self, destination: L3Address) -> Optional[int]:
     if not isinstance(destination, l3.NetRomAddress):
         print(f"Wrong address family, expected NET/ROM got {destination.__class__}")
         return None
     netrom_dest = cast(l3.NetRomAddress, destination)
     packet_dest = AX25Call(netrom_dest.callsign, netrom_dest.ssid)
     # TODO handle alias here
     if packet_dest in self.neighbors:
         return self.neighbors.get(str(packet_dest)).port
     else:
         dest = self.destinations.get(str(packet_dest))
         if dest:
             neighbors = dest.sorted_neighbors()
             if len(neighbors) > 0:
                 return self.neighbors.get(str(neighbors[0].neighbor)).port
             else:
                 return None
         else:
             return None
Ejemplo n.º 23
0
    def receive_frame(self, frame: FrameData):
        try:
            ax25_packet = decode_ax25_packet(frame.data)
            self.maybe_create_logical_link(ax25_packet.source)
            if ax25_packet.dest == AX25Call("NODES"):
                packet_logger.info(f"RX: {ax25_packet}")
                # Eagerly connect to neighbors sending NODES
                if self.state_machine.get_state(
                        ax25_packet.source) in (AX25StateType.Disconnected,
                                                AX25StateType.AwaitingRelease):
                    self.dl_connect_request(copy(ax25_packet.source))
            else:
                packet_logger.debug(f"RX: {ax25_packet}")
        except Exception:
            self.exception(f"Had error parsing packet: {frame}")
            return

        try:
            self.state_machine.handle_packet(ax25_packet)
        except Exception:
            self.exception(f"Had error handling packet {ax25_packet}")
Ejemplo n.º 24
0
 def _send_cq(self):
     event = AX25StateEvent.dl_unit_data(AX25Call("CQ"),
                                         L3Protocol.NoLayer3,
                                         "http://tarpn.net".encode("utf-8"))
     self.state_machine.handle_internal_event(event)
     self.cq_timer.reset()
Ejemplo n.º 25
0
    def data_received(self, data: bytes) -> None:
        s = data.decode("ASCII").strip().upper()
        self.info(f"Data: {s}")

        if self.pending_open is not None:
            self.println(f"Pending connection to {self.pending_open}")

        # If connected somewhere else, forward the input
        if self.client_transport:
            if s == "B" or s == "BYE":
                self.client_transport.close()
                self.println(
                    f"Closing connection to {self.client_transport.remote_call}...",
                    True)
            else:
                self.client_transport.write(data)
            return

        # If not forwarding, parse the command
        try:
            parsed_args = self.parser.parse_args(shlex.split(s.lower()))
        except BaseException:
            self.println(self.parser.format_help(), True)
            return

        if parsed_args.command is None:
            parsed_args.command = "help"
        if parsed_args.command == "help":
            self.println(self.parser.format_help(), True)
        elif parsed_args.command == "ports":
            resp = "Ports:\n"
            for dlm in self.datalinks:
                resp += f"{dlm.link_port}: {dlm.link_call}\n"
            self.println(resp, True)
        elif parsed_args.command == "links":
            resp = "Links:\n"
            for dlm in self.datalinks:
                for remote_call in dlm.state_machine.get_sessions().keys():
                    if dlm.state_machine.get_state(
                            str(remote_call)) == AX25StateType.Connected:
                        resp += f"L2 {dlm.link_call} > {str(remote_call)} on port {dlm.link_port}\n"
            for circuit_id in self.network.get_circuit_ids():
                circuit = self.network.get_circuit(circuit_id)
                if circuit.state == NetRomStateType.Connected:
                    resp += f"L3 {circuit.local_call} > {circuit.local_call} on circuit {circuit_id}\n"
            self.println(resp, True)
        elif parsed_args.command == "whoami":
            if isinstance(self.transport, NetworkTransport):
                nt = cast(NetworkTransport, self.transport)
                self.println(
                    f"Current user is {nt.origin_user.callsign} connected from {nt.origin_node}",
                    True)
            else:
                self.println(
                    f"Current user is default connected from {self.transport.get_extra_info('peername')}",
                    True)
        elif parsed_args.command == "hostname":
            self.println(f"Current host is {self.network.local_call()}", True)
        elif parsed_args.command == "bye":
            self.println("Goodbye.")
            self.transport.close()
        elif parsed_args.command == "connect":
            """
            Connect to a remote station
            
            Create a half-opened client connection to the remote station. Once the connect ack is received, 
            the connection will be completed and we will create the protocol and transport objects.
            """
            remote_call = AX25Call.parse(parsed_args.dest)
            local_call = AX25Call.parse(
                self.settings.network_configs().node_call())
            self.println(f"Connecting to {remote_call}...", True)

            if isinstance(self.transport, NetworkTransport):
                nt = cast(NetworkTransport, self.transport)
                self.network.open(partial(ConnectProtocol, self), local_call,
                                  remote_call, nt.origin_node, nt.origin_user)
                self.pending_open = remote_call
            else:
                logging.warning(
                    f"Connect command is only supported for NetworkTransport, not {self.transport.__class__}"
                )
                self.println(
                    f"Connect command is only supported for NetworkTransport",
                    True)

        else:
            logging.warning(f"Unhandled command {parsed_args.command}")
            self.println(f"Unhandled command {parsed_args.command}", True)
Ejemplo n.º 26
0
def main():
    parser = argparse.ArgumentParser(description='Decode packets from a serial port')
    parser.add_argument("port", help="Serial port to open")
    parser.add_argument("baud", type=int, help="Baudrate to use")
    parser.add_argument("local_call", help="Your callsign (e.g., K4DBZ-10)")
    parser.add_argument("local_alias", help="Your alias (e.g., ZDBZ10)")
    parser.add_argument("remote_call", help="Remote callsign")
    parser.add_argument("-datalink", help="Force L2 mode", action="store_true")
    parser.add_argument("--check-crc", type=bool, default=False)
    parser.add_argument("--monitor-port", type=int)
    parser.add_argument("--debug", action="store_true")
    args = parser.parse_args()

    # Configure logging
    main_logger = logging.getLogger("root")
    main_logger.setLevel(logging.ERROR)
    if args.debug:
        main_logger.setLevel(logging.DEBUG)

        state_logger = logging.getLogger("ax25.state")
        state_logger.setLevel(logging.DEBUG)
        state_logger.addHandler(logging.StreamHandler(sys.stdout))

        state_logger = logging.getLogger("netrom.state")
        state_logger.setLevel(logging.DEBUG)
        state_logger.addHandler(logging.StreamHandler(sys.stdout))

    scheduler = Scheduler()

    # Configure and initialize I/O device and L2
    port_config = PortConfig.from_dict(0, {
        "port.enabled": True,
        "port.type": "serial",
        "serial.device": args.port,
        "serial.speed": args.baud
    })

    # Initialize I/O device and L2
    l3_protocols = L3Protocols()
    l2_multi = DefaultLinkMultiplexer(L3PriorityQueue, scheduler)
    l2_queueing = L2FIFOQueue(20, AX25Protocol.maximum_frame_size())
    l2 = AX25Protocol(port_config, port_config.port_id(), AX25Call.parse(args.local_call), scheduler,
                      l2_queueing, l2_multi, l3_protocols)
    kiss = KISSProtocol(port_config.port_id(), l2_queueing, port_config.get_boolean("kiss.checksum", False))
    SerialDevice(kiss,
                 port_config.get("serial.device"),
                 port_config.get_int("serial.speed"),
                 port_config.get_float("serial.timeout"),
                 scheduler)
    scheduler.submit(L2IOLoop(l2_queueing, l2))

    # Initialize L3 and L4
    network_config = NetworkConfig.from_dict({
        "netrom.node.call": args.local_call,
        "netrom.node.alias": args.local_alias,
        "netrom.ttl": 7,
        "netrom.nodes.interval": 60,
        "netrom.obs.init": 6,
        "netrom.obs.min": 4,
        "netrom.nodes.quality.min": 74
    })

    # Register L3 protocols
    netrom_l3 = NetRomL3(AX25Call.parse(network_config.node_call()), network_config.node_alias(),
                         scheduler, l2_multi, NetRomRoutingTable(network_config.node_alias()))
    l3_protocols.register(netrom_l3)

    # Create the L4 protocol
    netrom_l4 = NetRomTransportProtocol(network_config, netrom_l3, scheduler)

    async def wait_for_network():
        tty = TTY()
        loop.add_reader(sys.stdin, tty.handle_stdin)
        loop.add_signal_handler(signal.SIGTERM, tty.handle_signal, loop, scheduler)
        loop.add_signal_handler(signal.SIGINT, tty.handle_signal, loop, scheduler)

        remote_call = AX25Call.parse(args.remote_call)
        while True:
            (found, mtu) = netrom_l3.route_packet(NetRomAddress.from_call(remote_call))
            if found:
                break
            await asyncio.sleep(0.200)
        main_logger.info(f"Learned route to {remote_call}")
        await asyncio.sleep(1.200)
        netrom_l4.open(protocol_factory=lambda: tty,
                       local_call=AX25Call.parse(args.local_call),
                       remote_call=AX25Call.parse(args.remote_call),
                       origin_user=AX25Call(args.local_alias),
                       origin_node=AX25Call(args.local_call))

    loop = asyncio.get_event_loop()
    loop.create_task(wait_for_network())

    try:
        loop.run_forever()
    finally:
        loop.close()
Ejemplo n.º 27
0
 def local_call(self) -> AX25Call:
     return AX25Call.parse(self.config.node_call())
Ejemplo n.º 28
0
 def to_ax25_call(self):
     return AX25Call(self.callsign, self.ssid)
Ejemplo n.º 29
0
async def main_async():
    parser = argparse.ArgumentParser(
        description='Decode packets from a serial port')
    parser.add_argument("config", help="Config file")
    parser.add_argument("--debug", action="store_true")

    args = parser.parse_args()

    s = Settings(".", args.config)
    node_settings = s.node_config()

    # Create the main event loop
    loop = asyncio.get_event_loop()

    dlms = []
    for port_config in s.port_configs():
        in_queue: asyncio.Queue = asyncio.Queue()
        out_queue: asyncio.Queue = asyncio.Queue()
        asyncio.create_task(kiss_port_factory(in_queue, out_queue,
                                              port_config))

        # Wire the port with an AX25 layer
        dlm = DataLinkManager(AX25Call.parse(node_settings.node_call()),
                              port_config.port_id(), in_queue, out_queue,
                              loop.create_future)
        dlms.append(dlm)

    # Wire up Layer 3 and default L2 app
    nl = NetworkManager(s.network_configs(), loop)
    for dlm in dlms:
        nl.attach_data_link(dlm)
        dlm.add_l3_handler(IdHandler())

    # Bind apps to netrom and start running the app servers
    for app_config in s.app_configs():
        # This multiplexer bridges the unix socket server and the network connections
        multiplexer = TransportMultiplexer()

        # We have a single unix socket connection
        unix_factory = partial(NetromAppProtocol, app_config.app_name(),
                               AX25Call.parse(app_config.app_call()),
                               app_config.app_alias(), nl, multiplexer)
        logger.info(
            f"Creating unix socket server for {app_config.app_call()} at {app_config.app_socket()}"
        )
        await loop.create_unix_server(unix_factory,
                                      app_config.app_socket(),
                                      start_serving=True)

        # And many network connections
        network_factory = partial(MultiplexingProtocol, multiplexer)
        nl.bind_server(AX25Call.parse(app_config.app_call()),
                       app_config.app_alias(), network_factory)

    node_app_factory = partial(CommandProcessorProtocol, s, dlms, nl)
    for dlm in dlms:
        # TODO add a bind_server thing here too?
        dlm.add_l3_handler(DataLinkAdapter(dlm, node_app_factory))

    node_call = s.network_configs().node_call()
    node_alias = s.network_configs().node_alias()

    # Make a default application for L4
    nl.bind_server(AX25Call.parse(node_call), node_alias, node_app_factory)

    if node_settings.admin_enabled():
        await loop.create_server(protocol_factory=node_app_factory,
                                 host=node_settings.admin_listen(),
                                 port=node_settings.admin_port(),
                                 start_serving=True)

    # Configure logging
    logging.config.fileConfig("config/logging.ini",
                              disable_existing_loggers=False)

    event_logger = logging.getLogger("events")
    event_logger.setLevel(logging.INFO)
    event_logger.addHandler(handler)

    # Start processing packets
    tasks = [dlm.start() for dlm in dlms]
    tasks.append(nl.start())
    logger.info("Packet engine started")
    await asyncio.wait(tasks)
Ejemplo n.º 30
0
 def from_safe_dict(cls, d):
     return cls(neighbor=AX25Call.parse(d["neighbor"]),
                dest=AX25Call.parse(d["destination"]),
                next_hop=AX25Call.parse(d["next_hop"]),
                quality=d["quality"],
                obsolescence=d["obsolescence"])