From cbaa9833a6a8e553fd658104dd7dfecf504ca598 Mon Sep 17 00:00:00 2001 From: Panos Vouzis Date: Thu, 9 Jan 2020 16:12:56 -0500 Subject: [PATCH] feat: added interface option to fast_com example (nbfast). --- fast_com.py | 2 - fast_com.pyc | Bin 4795 -> 4747 bytes fast_com_example_usage.py | 25 +++++++- patch_socket_create_connection.py | 92 ++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 3 deletions(-) create mode 100755 patch_socket_create_connection.py diff --git a/fast_com.py b/fast_com.py index 23abe85..c13af6b 100644 --- a/fast_com.py +++ b/fast_com.py @@ -218,5 +218,3 @@ def fast_com(verbose=False, maxtime=15, forceipv4=False, forceipv6=False): fast_com(verbose=True, maxtime=30) print "\ndone" - - diff --git a/fast_com.pyc b/fast_com.pyc index 3b667818fa11e6e181d134257c758fe81681796f..05fe804c2c389039a43e739091ad2d4855535a65 100644 GIT binary patch delta 161 zcmdn3+O5jL{F#@_WvY1GMh;_UAz20n2K|iu+*JL7O#QUP;*$8uq0AGp2ybGMWW*vo g*^W(mvLEX;EK-~8*cNhP6aUE{$b?0Fa*9wm0924Jt^fc4 delta 222 zcmeBH-L1;O{F#^Q;j-ZHjU2|zQmPCL4Eh=QxvBcaiFqlhMf&NPCHiTJ#U*-^eVHfX vk>31)S&|Wt{N#)LqLU3+?+{kPw%L-cjT4W$%@_FtnefO1trD5+A><4IR0KvK diff --git a/fast_com_example_usage.py b/fast_com_example_usage.py index e040943..2b986e0 100755 --- a/fast_com_example_usage.py +++ b/fast_com_example_usage.py @@ -1,4 +1,27 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 +import argparse + +parser = argparse.ArgumentParser(description='Run speed test.') +parser.add_argument('-4', '--ipv4', dest='ipv4', help='IPv4 source address') +parser.add_argument('-6', '--ipv6', dest='ipv6', help='IPv6 source address') +parser.add_argument('-i', '--interface', dest='interface', help='Set network interface') +parser.add_argument('-t', '--timeout', help='HTTP timeout in seconds.') + +args = parser.parse_args() +ipv4_source = None +ipv6_source = None + +ipv4_source = args.ipv4 +ipv6_source = args.ipv6 +network_interface = args.interface +network_timeout = args.timeout + +import socket +from patch_socket_create_connection import CustomSocket +my_socket = CustomSocket( + ipv4_source=ipv4_source, ipv6_source=ipv6_source, + network_interface=network_interface, network_timeout=network_timeout) +socket.create_connection = my_socket.create_connection_with_custom_network_interface import fast_com diff --git a/patch_socket_create_connection.py b/patch_socket_create_connection.py new file mode 100755 index 0000000..0dc5740 --- /dev/null +++ b/patch_socket_create_connection.py @@ -0,0 +1,92 @@ +import socket +import sys +from IN import SO_BINDTODEVICE + +class CustomSocket(object): + def __init__(self, + network_interface=None, + ipv4_source=None, ipv6_source=None, + network_timeout=None): + + if network_interface is not None: + network_interface = network_interface.strip()[:15] + '\0' + self.network_interface = network_interface + + if network_timeout is not None: + network_timeout = float(network_timeout) + self.network_timeout = network_timeout + + if ipv6_source is not None: + parsed_ipv6_source = self.parse_source_address(ipv6_source) + ipv6_source = self.extract_source_address_from_ipv6(parsed_ipv6_source) + self.ipv6_source = ipv6_source + + if ipv4_source is not None: + ipv4_source = self.parse_source_address(ipv4_source) + self.ipv4_source = ipv4_source + + @staticmethod + def parse_source_address(source_addr): + source_addr = source_addr.split(',') + if len(source_addr) == 1: + return (source_addr[0], 0) + return (source_addr[0], int(source_addr[1])) + + @staticmethod + def extract_source_address_from_ipv6(ipv6_source): + source_ip, source_port = ipv6_source + source_address = [addr for addr in socket.getaddrinfo(source_ip, source_port, socket.AF_INET6, socket.SOCK_STREAM, socket.SOL_TCP)] + if not source_address: + raise ValueError("Couldn't find ipv6 address for source %s" % source_ip) + return source_address[0][-1] + + def get_source_address(self, host): + if ':' in host: + return self.ipv6_source + + return self.ipv4_source + + def create_connection_with_custom_network_interface( + self, address, timeout, source_address=None): + """ + Patched the standard library (v2.7.3) socket.create_connection to + connect to a network interface. + + https://github.com/enthought/Python-2.7.3/blob/master/Lib/socket.py#L537 + """ + host, port = address + + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + + if source_address is None: + source_address = self.get_source_address(host) + + if self.network_interface: + try: + sock.setsockopt(socket.SOL_SOCKET, + SO_BINDTODEVICE, + self.network_interface) + except Exception as e: + err_msg = "No device exists: {}".format(self.network_interface) + sys.exit(err_msg) + elif source_address: + sock.bind(source_address) + + if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: + sock.settimeout(timeout) + elif self.network_timeout: + sock.settimeout(self.network_timeout) + + sock.connect(sa) + + return sock + except socket.error as err: + if sock: + sock.close() + raise err + + raise error("getaddrinfo returns an empty list") \ No newline at end of file