mirror of
https://github.com/meshtastic/python.git
synced 2025-12-31 11:57:57 -05:00
Add traceroute option
This commit is contained in:
@@ -183,5 +183,6 @@ protocols = {
|
||||
portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing),
|
||||
portnums_pb2.PortNum.TELEMETRY_APP: KnownProtocol("telemetry", telemetry_pb2.Telemetry),
|
||||
portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol("remotehw", remote_hardware_pb2.HardwareMessage),
|
||||
portnums_pb2.PortNum.SIMULATOR_APP: KnownProtocol("simulator", mesh_pb2.Compressed)
|
||||
portnums_pb2.PortNum.SIMULATOR_APP: KnownProtocol("simulator", mesh_pb2.Compressed),
|
||||
portnums_pb2.PortNum.TRACEROUTE_APP: KnownProtocol("traceroute", mesh_pb2.RouteDiscovery)
|
||||
}
|
||||
|
||||
@@ -330,6 +330,13 @@ def onConnected(interface):
|
||||
interface.sendData(payload, args.dest, portNum=portnums_pb2.PortNum.REPLY_APP,
|
||||
wantAck=True, wantResponse=True)
|
||||
|
||||
if args.traceroute:
|
||||
loraConfig = getattr(interface.localNode.localConfig, 'lora')
|
||||
hopLimit = getattr(loraConfig, 'hop_limit')
|
||||
dest = str(args.traceroute)
|
||||
print(f"Sending traceroute request to {dest} (this could take a while)")
|
||||
interface.sendTraceRoute(dest, hopLimit)
|
||||
|
||||
if args.gpio_wrb or args.gpio_rd or args.gpio_watch:
|
||||
if args.dest == BROADCAST_ADDR:
|
||||
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
|
||||
@@ -935,6 +942,12 @@ def initParser():
|
||||
parser.add_argument(
|
||||
"--sendping", help="Send a ping message (which requests a reply)", action="store_true")
|
||||
|
||||
parser.add_argument(
|
||||
"--traceroute", help="Traceroute from connected node to a destination. " \
|
||||
"You need pass the destination ID as argument, like " \
|
||||
"this: '--traceroute !ba4bf9d0' " \
|
||||
"Only nodes that have the encryption key can be traced.")
|
||||
|
||||
parser.add_argument(
|
||||
"--reboot", help="Tell the destination node to reboot", action="store_true")
|
||||
|
||||
|
||||
@@ -291,6 +291,27 @@ class MeshInterface:
|
||||
portNum=portnums_pb2.PortNum.POSITION_APP,
|
||||
wantAck=wantAck,
|
||||
wantResponse=wantResponse)
|
||||
|
||||
def sendTraceRoute(self, dest, hopLimit):
|
||||
r = mesh_pb2.RouteDiscovery()
|
||||
self.sendData(r, destinationId=dest, portNum=70, wantResponse=True, onResponse=self.onResponseTraceRoute)
|
||||
waitFactor = min(len(self.nodes)-1, hopLimit) # extend timeout based on number of nodes, limit by configured hopLimit
|
||||
self.waitForTraceRoute(waitFactor)
|
||||
|
||||
def onResponseTraceRoute(self, p):
|
||||
routeDiscovery = mesh_pb2.RouteDiscovery()
|
||||
routeDiscovery.ParseFromString(p["decoded"]["payload"])
|
||||
asDict = google.protobuf.json_format.MessageToDict(routeDiscovery)
|
||||
|
||||
print("Route traced:")
|
||||
routeStr = self._nodeNumToId(p["to"])
|
||||
if "route" in asDict:
|
||||
for nodeNum in asDict["route"]:
|
||||
routeStr += " --> " + self._nodeNumToId(nodeNum)
|
||||
routeStr += " --> " + self._nodeNumToId(p["from"])
|
||||
print(routeStr)
|
||||
|
||||
self._acknowledgment.receivedTraceRoute = True
|
||||
|
||||
def _addResponseHandler(self, requestId, callback):
|
||||
self.responseHandlers[requestId] = ResponseHandler(callback)
|
||||
@@ -365,6 +386,11 @@ class MeshInterface:
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for an acknowledgment")
|
||||
|
||||
def waitForTraceRoute(self, waitFactor):
|
||||
success = self._timeout.waitForTraceRoute(waitFactor, self._acknowledgment)
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for traceroute")
|
||||
|
||||
def getMyNodeInfo(self):
|
||||
"""Get info about my node."""
|
||||
if self.myInfo is None:
|
||||
|
||||
@@ -169,17 +169,30 @@ class Timeout:
|
||||
time.sleep(self.sleepInterval)
|
||||
return False
|
||||
|
||||
def waitForTraceRoute(self, waitFactor, acknowledgment, attr='receivedTraceRoute'):
|
||||
"""Block until traceroute response is received. Returns True if traceroute response has been received."""
|
||||
self.expireTimeout *= waitFactor
|
||||
self.reset()
|
||||
while time.time() < self.expireTime:
|
||||
if getattr(acknowledgment, attr, None):
|
||||
acknowledgment.reset()
|
||||
return True
|
||||
time.sleep(self.sleepInterval)
|
||||
return False
|
||||
|
||||
class Acknowledgment:
|
||||
"A class that records which type of acknowledgment was just received, if any."
|
||||
def __init__(self):
|
||||
self.receivedAck = False
|
||||
self.receivedNak = False
|
||||
self.receivedImplAck = False
|
||||
self.receivedTraceRoute = False
|
||||
|
||||
def reset(self):
|
||||
self.receivedAck = False
|
||||
self.receivedNak = False
|
||||
self.receivedImplAck = False
|
||||
self.receivedTraceRoute = False
|
||||
|
||||
class DeferredExecution():
|
||||
"""A thread that accepts closures to run, and runs them as they are received"""
|
||||
|
||||
Reference in New Issue
Block a user