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.
This commit is contained in:
Martin Turon
2016-09-12 09:50:25 -07:00
committed by Jonathan Hui
parent d8f9e5baa0
commit bb84b9a1f2
3 changed files with 57 additions and 56 deletions
+57 -53
View File
@@ -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: