From bb84b9a1f2162fd43fef984dd00a2eb2ed3df425 Mon Sep 17 00:00:00 2001 From: Martin Turon Date: Mon, 12 Sep 2016 09:50:25 -0700 Subject: [PATCH] spinel-cli: Stability improvements to ping (#561) * Improve ping reliability by making it fully async. Eliminate 5_1_07 from XFAIL list. * Some non-core changes: readd missing StreamSocket class, improve handling of command. --- .travis.yml | 2 - tests/scripts/Makefile.am | 1 - tools/spinel-cli/spinel-cli.py | 110 +++++++++++++++++---------------- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/.travis.yml b/.travis.yml index 86f7f056b..24ebf944a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,5 +63,3 @@ matrix: - env: BUILD_TARGET="posix-ncp" VERBOSE=1 compiler: gcc os: linux - allow_failures: - - env: BUILD_TARGET="posix-ncp" VERBOSE=1 diff --git a/tests/scripts/Makefile.am b/tests/scripts/Makefile.am index 4794f965a..8fa589075 100644 --- a/tests/scripts/Makefile.am +++ b/tests/scripts/Makefile.am @@ -232,7 +232,6 @@ TESTS = \ $(NULL) XFAIL_NCP_TESTS = \ - thread-cert/Cert_5_1_07_MaxChildCount.py \ thread-cert/Cert_5_3_07_DuplicateAddress.py \ thread-cert/Cert_5_6_01_NetworkDataRegisterBeforeAttachLeader.py \ thread-cert/Cert_5_6_02_NetworkDataRegisterBeforeAttachRouter.py \ diff --git a/tools/spinel-cli/spinel-cli.py b/tools/spinel-cli/spinel-cli.py index df926634a..34dda5248 100755 --- a/tools/spinel-cli/spinel-cli.py +++ b/tools/spinel-cli/spinel-cli.py @@ -63,8 +63,6 @@ DEBUG_LOG_TUN = 0 DEBUG_TERM = 0 DEBUG_CMD_RESPONSE = 0 - -TIMEOUT_PING = 2 TIMEOUT_PROP = 2 gWpanApi = None @@ -73,7 +71,7 @@ def goodbye(signum=None, frame=None): logger.info('\nQuitting') if gWpanApi: gWpanApi.serial.close() - exit(1) + exit(0) import os import sys @@ -113,6 +111,7 @@ from select import select logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import IPv6 from scapy.all import ICMPv6EchoRequest +from scapy.all import ICMPv6EchoReply MASTER_PROMPT = "spinel-cli" @@ -181,10 +180,6 @@ class Color: DARKCYAN = "\033[36m" WHITE = "\033[37m" -IP_TYPE_UDP = 17 -IP_TYPE_ICMPv6 = 58 - - SPINEL_RSSI_OVERRIDE = 127 SPINEL_HEADER_ASYNC = 0x80 @@ -589,6 +584,21 @@ class StreamSerial(IStream): logger.debug("RX Raw: "+hexify_bytes(b)) return b +class StreamSocket(IStream): + def __init__(self, sock): + self.sock = sock + + def write(self, data): + self.sock.send(data) + if DEBUG_LOG_TX: + logger.debug("TX Raw: "+str(map(hexify_chr,data))) + + def read(self, size=1): + b = self.sock.recv(size) + if DEBUG_LOG_RX_BYTES: + logger.debug("RX Raw: "+str(map(hexify_chr,b))) + return b + class StreamPipe(IStream): def __init__(self, filename): """ Create a stream object from a piped system call """ @@ -979,6 +989,9 @@ class SpinelCommandHandler(SpinelCodec): pkt = IPv6(prop_value[2:]) pkt.show() + elif (prop_op == SPINEL_PROP_STREAM_DEBUG): + logger.debug("DEBUG: "+prop_value) + if gWpanApi: gWpanApi.queue_add(prop_op, prop_value, tid) else: @@ -1214,7 +1227,6 @@ class WpanApi(SpinelCodec): self.__queue_prop = Queue.Queue() self.__start_reader() self.tid_filter = SPINEL_HEADER_DEFAULT - self.ip_type_filter = IP_TYPE_ICMPv6 def __del__(self): self._reader_alive = False @@ -1274,8 +1286,7 @@ class WpanApi(SpinelCodec): def serial_rx(self): - # Recieve thread and parser - + """ Recieve thread and parser. """ while self._reader_alive: if self.useHdlc: self.rx_pkt = self.hdlc.collect() @@ -1297,15 +1308,18 @@ class WpanApi(SpinelCodec): def queue_wait_prepare(self, prop_id, tid=SPINEL_HEADER_DEFAULT): self.tid_filter = tid self.prop_filter = prop_id - #print "Q tid_filter = "+str(self.tid_filter) self.queue_clear() def queue_add(self, prop, value, tid): - #print "Q add: tid="+str(tid)+" prop="+str(prop)+" tid_filter="+str(self.tid_filter) - if (tid != self.tid_filter) or (prop != self.prop_filter): return - if (self.prop_filter == SPINEL_PROP_STREAM_NET): + # Asynchronous handlers don't actually add to queue. + if (prop == SPINEL_PROP_STREAM_NET): pkt = IPv6(value[2:]) - if pkt.nh != self.ip_type_filter: return + if ICMPv6EchoReply in pkt: + print "\n%d bytes from %s: icmp_seq=%d hlim=%d time=%dms" % ( + pkt.plen, pkt.src, pkt.seq, pkt.hlim, 80) + return + + if (tid != self.tid_filter) or (prop != self.prop_filter): return item = self.PropertyItem(prop, value, tid) self.__queue_prop.put_nowait(item) @@ -1320,15 +1334,12 @@ class WpanApi(SpinelCodec): return None while (item): - #print "Q rx: tid="+str(item.tid)+" prop="+str(item.prop) if (item.tid == self.tid_filter) and (item.prop == prop): return item if (self.__queue_prop.empty()): - #logger.debug("Q rx: wrong response") return None else: item = self.__queue_prop.get_nowait() - #logger.debug("Q rx: null item") return None @@ -1402,6 +1413,11 @@ class WpanApi(SpinelCodec): class WpanDiagsCmd(Cmd, SpinelCodec): def __init__(self, device, *a, **kw): + + self.wpanApi = WpanApi(device) + global gWpanApi + gWpanApi = self.wpanApi + Cmd.__init__(self) Cmd.identchars = string.ascii_letters + string.digits + '-' @@ -1431,12 +1447,6 @@ class WpanDiagsCmd(Cmd, SpinelCodec): if sys.platform == 'darwin': readline.parse_and_bind("bind ^I rl_complete") - - # === Initialize Shell with some important parameters == - self.wpanApi = WpanApi(device) - global gWpanApi - gWpanApi = self.wpanApi - self.nodeid = kw.get('nodeid','1') self.prop_set_value(SPINEL_PROP_THREAD_RLOC16_DEBUG_PASSTHRU, 1) self.prop_set_value(SPINEL_PROP_IPv6_ICMP_PING_OFFLOAD, 1) @@ -1698,16 +1708,22 @@ class WpanDiagsCmd(Cmd, SpinelCodec): Usage: debug <1=enable | 0=disable> """ global DEBUG_ENABLE, DEBUG_LOG_PKT, DEBUG_LOG_PROP - global DEBUG_LOG_TX, DEBUG_LOG_RX + global DEBUG_LOG_TX, DEBUG_LOG_RX, DEBUG_LOG_HDLC + + if line != None and line != "": + level = int(line) + + if level: + DEBUG_ENABLE = level + if level >= 1: DEBUG_LOG_PROP = 1 + if level >= 2: DEBUG_LOG_PKT = 1 + if level >= 3: DEBUG_LOG_HDLC = 1 + else: + DEBUG_ENABLE = 0 + DEBUG_LOG_PROP = 0 + DEBUG_LOG_PKT = 0 + DEBUG_LOG_HDLC = 0 - if line: line = int(line) - if line: - DEBUG_ENABLE = 1 - else: - DEBUG_ENABLE = 0 - #DEBUG_LOG_TX = DEBUG_ENABLE - DEBUG_LOG_PKT = DEBUG_ENABLE - DEBUG_LOG_PROP = DEBUG_ENABLE print "DEBUG_ENABLE = "+str(DEBUG_ENABLE) def do_debugterm(self, line): @@ -2275,20 +2291,8 @@ class WpanDiagsCmd(Cmd, SpinelCodec): ML64 = self.prop_get_value(SPINEL_PROP_IPV6_ML_ADDR) ML64 = str(ipaddress.IPv6Address(ML64)) ping_req = str(IPv6(src=ML64, dst=addr)/ICMPv6EchoRequest()) - self.wpanApi.queue_wait_prepare(SPINEL_PROP_STREAM_NET, - SPINEL_HEADER_ASYNC) self.wpanApi.ip_send(ping_req) - result = self.wpanApi.queue_wait_for_prop(SPINEL_PROP_STREAM_NET, - TIMEOUT_PING) - if result: - pkt = IPv6(result.value[2:]) - print "%d bytes from %s: icmp_seq=%d hlim=%d time=%dms" % ( - pkt.plen, pkt.src, pkt.seq, pkt.hlim, 80) - print("Done") - else: - # Don't output anything when ping fails - #print "Fail" - pass + # Let handler print result except: print "Fail" print traceback.format_exc() @@ -2944,6 +2948,13 @@ class WpanDiagsCmd(Cmd, SpinelCodec): if __name__ == "__main__": + # register clean exit handlers. + signal.signal(signal.SIGHUP, goodbye) + signal.signal(signal.SIGINT, goodbye) + signal.signal(signal.SIGCONT, goodbye) + signal.signal(signal.SIGABRT, goodbye) + signal.signal(signal.SIGTERM, goodbye) + signal.signal(signal.SIGPIPE, goodbye) args = sys.argv[1:] @@ -2985,13 +2996,6 @@ if __name__ == "__main__": stream = StreamOpen(streamType, streamDescriptor) shell = WpanDiagsCmd(stream, nodeid=options.nodeid) - # register clean exit handlers. - signal.signal(signal.SIGHUP, goodbye) - signal.signal(signal.SIGINT, goodbye) - signal.signal(signal.SIGABRT, goodbye) - signal.signal(signal.SIGTERM, goodbye) - signal.signal(signal.SIGPIPE, goodbye) - try: shell.cmdloop() except KeyboardInterrupt: