From 034f11b4f9f3392e003cfbd0e5f8b9fb5f594089 Mon Sep 17 00:00:00 2001 From: Walter Boring Date: Fri, 6 Jun 2025 17:18:19 -0400 Subject: [PATCH] Make sure packet has addressee field Before dereferencing it in the rx thread. This covers the case for an Unknown Packet --- aprsd/packets/core.py | 2 +- aprsd/packets/log.py | 128 +++++++++++++++++++++++------------------- aprsd/threads/rx.py | 7 ++- 3 files changed, 75 insertions(+), 62 deletions(-) diff --git a/aprsd/packets/core.py b/aprsd/packets/core.py index bc4397e..7c7991f 100644 --- a/aprsd/packets/core.py +++ b/aprsd/packets/core.py @@ -674,7 +674,7 @@ class ThirdPartyPacket(Packet, DataClassJsonMixin): @dataclass_json(undefined=Undefined.INCLUDE) @dataclass(unsafe_hash=True) -class UnknownPacket: +class UnknownPacket(Packet): """Catchall Packet for things we don't know about. All of the unknown attributes are stored in the unknown_fields diff --git a/aprsd/packets/log.py b/aprsd/packets/log.py index f3905f6..bbee973 100644 --- a/aprsd/packets/log.py +++ b/aprsd/packets/log.py @@ -12,13 +12,13 @@ LOG = logging.getLogger() LOGU = logger CONF = cfg.CONF -FROM_COLOR = "fg #C70039" -TO_COLOR = "fg #D033FF" -TX_COLOR = "red" -RX_COLOR = "green" -PACKET_COLOR = "cyan" -DISTANCE_COLOR = "fg #FF5733" -DEGREES_COLOR = "fg #FFA900" +FROM_COLOR = 'fg #C70039' +TO_COLOR = 'fg #D033FF' +TX_COLOR = 'red' +RX_COLOR = 'green' +PACKET_COLOR = 'cyan' +DISTANCE_COLOR = 'fg #FF5733' +DEGREES_COLOR = 'fg #FFA900' def log_multiline( @@ -27,11 +27,11 @@ def log_multiline( """LOG a packet to the logfile.""" if not CONF.enable_packet_logging: return - if CONF.log_packet_format == "compact": + if CONF.log_packet_format == 'compact': return # asdict(packet) - logit = ["\n"] + logit = ['\n'] name = packet.__class__.__name__ if isinstance(packet, AckPacket): @@ -41,57 +41,67 @@ def log_multiline( if header: if tx: - header_str = f"<{TX_COLOR}>TX" + header_str = f'<{TX_COLOR}>TX' logit.append( - f"{header_str}________(<{PACKET_COLOR}>{name} " - f"TX:{packet.send_count + 1} of {pkt_max_send_count}", + f'{header_str}________(<{PACKET_COLOR}>{name} ' + f'TX:{packet.send_count + 1} of {pkt_max_send_count}', ) else: - header_str = f"<{RX_COLOR}>RX" + header_str = f'<{RX_COLOR}>RX' logit.append( - f"{header_str}________(<{PACKET_COLOR}>{name})", + f'{header_str}________(<{PACKET_COLOR}>{name})', ) else: - header_str = "" - logit.append(f"__________(<{PACKET_COLOR}>{name})") + header_str = '' + logit.append(f'__________(<{PACKET_COLOR}>{name})') # log_list.append(f" Packet : {packet.__class__.__name__}") if packet.msgNo: - logit.append(f" Msg # : {packet.msgNo}") + logit.append(f' Msg # : {packet.msgNo}') if packet.from_call: - logit.append(f" From : <{FROM_COLOR}>{packet.from_call}") + logit.append(f' From : <{FROM_COLOR}>{packet.from_call}') if packet.to_call: - logit.append(f" To : <{TO_COLOR}>{packet.to_call}") - if hasattr(packet, "path") and packet.path: - logit.append(f" Path : {'=>'.join(packet.path)}") - if hasattr(packet, "via") and packet.via: - logit.append(f" VIA : {packet.via}") + logit.append(f' To : <{TO_COLOR}>{packet.to_call}') + if hasattr(packet, 'path') and packet.path: + logit.append(f' Path : {"=>".join(packet.path)}') + if hasattr(packet, 'via') and packet.via: + logit.append(f' VIA : {packet.via}') if not isinstance(packet, AckPacket) and not isinstance(packet, RejectPacket): msg = packet.human_info if msg: - msg = msg.replace("<", "\\<") - logit.append(f" Info : {msg}") + msg = msg.replace('<', '\\<') + logit.append(f' Info : {msg}') - if hasattr(packet, "comment") and packet.comment: - logit.append(f" Comment : {packet.comment}") + if hasattr(packet, 'comment') and packet.comment: + logit.append(f' Comment : {packet.comment}') - raw = packet.raw.replace("<", "\\<") - logit.append(f" Raw : {raw}") - logit.append(f"{header_str}________(<{PACKET_COLOR}>{name})") + raw = packet.raw.replace('<', '\\<') + logit.append(f' Raw : {raw}') + logit.append(f'{header_str}________(<{PACKET_COLOR}>{name})') - LOGU.opt(colors=True).info("\n".join(logit)) + LOGU.opt(colors=True).info('\n'.join(logit)) LOG.debug(repr(packet)) -def log(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> None: +def log( + packet, + tx: Optional[bool] = False, + header: Optional[bool] = True, + packet_count: Optional[int] = None, +) -> None: if not CONF.enable_packet_logging: return - if CONF.log_packet_format == "multiline": + if CONF.log_packet_format == 'multiline': log_multiline(packet, tx, header) return + if not packet_count: + packet_count = '' + else: + packet_count = f'({packet_count:d})' + logit = [] name = packet.__class__.__name__ if isinstance(packet, AckPacket): @@ -101,47 +111,47 @@ def log(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> No if header: if tx: - via_color = "red" - arrow = f"<{via_color}>\u2192" + via_color = 'red' + arrow = f'<{via_color}>\u2192' logit.append( - f"TX\u2191 " - f"{name}" - f":{packet.msgNo}" - f" ({packet.send_count + 1} of {pkt_max_send_count})", + f'TX{packet_count}\u2191 ' + f'{name}' + f':{packet.msgNo}' + f' ({packet.send_count + 1} of {pkt_max_send_count})', ) else: - via_color = "fg #1AA730" - arrow = f"<{via_color}>\u2192" - f"<{via_color}><-" + via_color = 'fg #1AA730' + arrow = f'<{via_color}>\u2192' + f'<{via_color}><-' logit.append( - f"RX\u2193 " - f"{name}" - f":{packet.msgNo}", + f'RX{packet_count}\u2193 ' + f'{name}' + f':{packet.msgNo}', ) else: - via_color = "green" - arrow = f"<{via_color}>->" + via_color = 'green' + arrow = f'<{via_color}>->' logit.append( - f"{name}" f":{packet.msgNo}", + f'{name}:{packet.msgNo}', ) tmp = None if packet.path: - tmp = f"{arrow}".join(packet.path) + f"{arrow} " + tmp = f'{arrow}'.join(packet.path) + f'{arrow} ' logit.append( - f"<{FROM_COLOR}>{packet.from_call} {arrow}" - f"{tmp if tmp else ' '}" - f"<{TO_COLOR}>{packet.to_call}", + f'<{FROM_COLOR}>{packet.from_call} {arrow}' + f'{tmp if tmp else " "}' + f'<{TO_COLOR}>{packet.to_call}', ) if not isinstance(packet, AckPacket) and not isinstance(packet, RejectPacket): - logit.append(":") + logit.append(':') msg = packet.human_info if msg: - msg = msg.replace("<", "\\<") - logit.append(f"{msg}") + msg = msg.replace('<', '\\<') + logit.append(f'{msg}') # is there distance information? if isinstance(packet, GPSPacket) and CONF.latitude and CONF.longitude: @@ -150,12 +160,12 @@ def log(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> No try: bearing = utils.calculate_initial_compass_bearing(my_coords, packet_coords) except Exception as e: - LOG.error(f"Failed to calculate bearing: {e}") + LOG.error(f'Failed to calculate bearing: {e}') bearing = 0 logit.append( - f" : <{DEGREES_COLOR}>{utils.degrees_to_cardinal(bearing, full_string=True)}" - f"<{DISTANCE_COLOR}>@{haversine(my_coords, packet_coords, unit=Unit.MILES):.2f}miles", + f' : <{DEGREES_COLOR}>{utils.degrees_to_cardinal(bearing, full_string=True)}' + f'<{DISTANCE_COLOR}>@{haversine(my_coords, packet_coords, unit=Unit.MILES):.2f}miles', ) - LOGU.opt(colors=True).info(" ".join(logit)) + LOGU.opt(colors=True).info(' '.join(logit)) log_multiline(packet, tx, header) diff --git a/aprsd/threads/rx.py b/aprsd/threads/rx.py index bf5f40e..5ee003f 100644 --- a/aprsd/threads/rx.py +++ b/aprsd/threads/rx.py @@ -32,6 +32,8 @@ class APRSDRXThread(APRSDThread): # getting blocked by the APRS server trying to send us packets. packet_queue = None + pkt_count = 0 + def __init__(self, packet_queue): super().__init__('RX_PKT') self.packet_queue = packet_queue @@ -91,7 +93,8 @@ class APRSDRXThread(APRSDThread): 'No packet received from decode_packet. Most likely a failure to parse' ) return - packet_log.log(packet) + self.pkt_count += 1 + packet_log.log(packet, packet_count=self.pkt_count) pkt_list = packets.PacketList() if isinstance(packet, packets.AckPacket): @@ -215,7 +218,7 @@ class APRSDProcessPacketThread(APRSDFilterThread): our_call = CONF.callsign.lower() from_call = packet.from_call - if packet.addresse: + if hasattr(packet, 'addresse') and packet.addresse: to_call = packet.addresse else: to_call = packet.to_call