UDP Test Tool
Addition of connection testing tool using UDP transmission to measure the rate
at which the link can be used.
Change-Id: Ia859b1c1a944c4abd0658ea3912a1d3389a46ed6
diff --git a/udp_test/options.py b/udp_test/options.py
new file mode 120000
index 0000000..3508154
--- /dev/null
+++ b/udp_test/options.py
@@ -0,0 +1 @@
+../options.py
\ No newline at end of file
diff --git a/udp_test/udp_test_client.py b/udp_test/udp_test_client.py
new file mode 100755
index 0000000..789fc68
--- /dev/null
+++ b/udp_test/udp_test_client.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+"""UDP test client.
+
+This implements the client side of the UDP connection testing tool to evaluate
+the effective speed of a link using bursts of UDP traffic.
+"""
+import select
+import socket
+import struct
+import sys
+import time
+
+import options
+
+optspec = """
+udp_test_client.py [options...] host_ip
+--
+i,interval= Specify the cycle interval in seconds [2.0]
+t,time= Specify the test length in seconds; zero means unlimited. [0]
+"""
+
+try:
+ import monotime
+except ImportError:
+ pass
+try:
+ monotime = time.monotime
+except AttributeError:
+ monotime = time.time
+
+
+def parse_address(raw_address):
+ port = 5001
+
+ raw_host_addr = raw_address.split(':')
+ if len(raw_host_addr) > 1:
+ port = int(raw_host_addr[1])
+
+ return (raw_host_addr[0], port)
+
+
+def main():
+ o = options.Options(optspec)
+ opt, _, extra = o.parse(sys.argv[1:])
+
+ interval_length = float(opt.interval)
+
+ host_addr = parse_address(extra[0])
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ packet_counter = 0
+ packets_sent = 0
+ packets_recv = 0
+ respond_time = monotime()
+ start_time = monotime()
+ server_count = 0
+ last_heard = monotime()
+
+ print 'Host Address: %s' % host_addr[0]
+
+ while True:
+ wait_time = interval_length - (monotime() - respond_time)
+ if wait_time < 0:
+ wait_time = 0
+ sock_ready, _, _ = select.select([sock], [], [], wait_time)
+ if sock_ready:
+ data = sock.recv(65536)
+ magic, pack_type = struct.unpack('!4s4s', data[0:8])
+
+ if magic != 'TPDO':
+ continue
+
+ if pack_type == 'RNNG':
+ packet_counter += 1
+ _, _, server_count = struct.unpack('!4s4si', data[0:12])
+ last_heard = monotime()
+ if monotime() - respond_time > interval_length:
+ temp_time = monotime()
+ counter_msg = struct.pack('!4s4siid', 'TPDO', 'UPDT', server_count,
+ packet_counter, temp_time)
+ sock.sendto(counter_msg, host_addr)
+
+ if packet_counter > 0:
+ cycle_time = temp_time - respond_time
+ send_rate = server_count - packets_sent
+ recv_rate = packet_counter - packets_recv
+ if send_rate == 0:
+ success_rate = 0
+ else:
+ success_rate = float(recv_rate) / send_rate
+
+ print ('Send Rate: %.2fMbps, Receive Rate: %.2fMbps, '
+ 'Success Rate: %.2f%%' %
+ (send_rate * len(data) * 8 / 1000000 / cycle_time,
+ recv_rate * len(data) * 8 / 1000000 / cycle_time,
+ success_rate * 100))
+
+ packets_sent = server_count
+ packets_recv = packet_counter
+ respond_time = monotime()
+ if monotime() - start_time > float(opt.time) and opt.time:
+ break
+
+ if monotime() - last_heard > interval_length * 4:
+ sys.stderr.write('Failed, Connection Timed out')
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/udp_test/udp_test_host.py b/udp_test/udp_test_host.py
new file mode 100755
index 0000000..b89e864
--- /dev/null
+++ b/udp_test/udp_test_host.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python
+"""UDP test host.
+
+This is the host-side implementation of a UDP test tool to evaluate the speed
+of a connection using bursts of UDP traffic
+"""
+import select
+import socket
+import struct
+import sys
+import time
+
+import options
+
+try:
+ import monotime
+except ImportError:
+ pass
+try:
+ monotime = time.monotime
+except AttributeError:
+ monotime = time.time
+
+optspec = """
+udp_test_host.py [options...]
+--
+p,port= Specify a port to use. [5001]
+s,size= Specify the packet size [1472]
+"""
+
+
+def main():
+ o = options.Options(optspec)
+ opt, _, _ = o.parse(sys.argv[1:])
+
+ port = int(opt.port)
+ send_rate = 1000.0 # Hz
+ current_index = 0
+ timeout_val = 10
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.bind(('', port))
+
+ client_addr = ('', 0)
+ last_client_time = 0
+ last_packets_sent = 0
+ last_packets_recv = 0
+ remainder_time = 0
+
+ cycle_counter = 0
+ cycle_time = monotime()
+ msg_length = int(opt.size)
+ counter_msg = bytearray('7' * msg_length)
+ while True:
+ # Account for processing time
+ sock_status, _, _ = select.select([sock], [], [], remainder_time)
+ if sock_status:
+ host_time = monotime()
+ data, addr = sock.recvfrom(65536)
+ magic, pack_type, server_count, client_count, new_time = struct.unpack(
+ '!4s4siid', data)
+ if magic != 'TPDO' or pack_type != 'UPDT':
+ print 'Invalid Packet'
+ continue
+ if addr != client_addr:
+ current_index = 0
+ send_rate = 1000.0 # Hz
+
+ client_addr = addr
+ cycle_time = monotime()
+ cycle_counter = 0
+ # Keeps track of last time client was heard from
+ last_packets_sent = last_packets_recv = 0
+ last_client_time = new_time
+ host_time = monotime()
+ print 'connection established with %s\n' % client_addr[0]
+ else:
+ # Calculate metrics for user
+ cycle_length = new_time - last_client_time
+ measured_pack_sent = (server_count - last_packets_sent) / cycle_length
+ measured_send_rate = measured_pack_sent * msg_length * 8 / 1000000
+ measured_recv_rate = ((client_count - last_packets_recv) /
+ cycle_length * msg_length * 8 / 1000000)
+ if server_count <= last_packets_sent:
+ success_rate = 0
+ else:
+ success_rate = (float(client_count - last_packets_recv) /
+ (server_count - last_packets_sent))
+
+ print ('\nAttempted Rate: %.2fMbps, Sending Rate: %.2fMbps, '
+ 'Receive Rate: %.2fMbps, Success Rate: %.2f%%'
+ % (send_rate * msg_length * 8 / 1000000,
+ measured_send_rate,
+ measured_recv_rate,
+ success_rate * 100))
+
+ cycle_time = monotime()
+ cycle_counter = 0
+ if float(success_rate) > 0.9:
+ send_rate = 1.1 * measured_pack_sent
+ elif float(success_rate) < 0.8:
+ send_rate = 0.9 * measured_pack_sent
+ else:
+ send_rate = measured_pack_sent
+
+ # Prevent the host from not sending any packets.
+ if send_rate <= 0:
+ send_rate = 10
+ last_packets_recv = client_count
+ last_packets_sent = server_count
+ last_client_time = new_time
+
+ elif client_addr != ('', 0):
+ # No packets from client received
+ burst_counter = 0
+ while True:
+ remainder_time = (cycle_counter + 1) / send_rate - (monotime() -
+ cycle_time)
+ if remainder_time > 0:
+ break
+ cycle_counter += 1
+ current_index += 1
+ counter_msg[0:12] = struct.pack('!4s4si', 'TPDO', 'RNNG', current_index)
+ sock.sendto(counter_msg, client_addr)
+ burst_counter += 1
+ if not current_index % (int(send_rate/10) + 1):
+ sys.stdout.write('.')
+ sys.stdout.flush()
+ if monotime() - host_time > timeout_val:
+ client_addr = ('', 0)
+ sys.stderr.write('\nconnection lost with client\n')
+ remainder_time = 0
+ break
+ if burst_counter > 1000:
+ remainder_time = 0
+ break
+
+if __name__ == '__main__':
+ main()
+