• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import re
7import socket
8import time
9import urllib2
10
11import common
12
13from autotest_lib.client.bin import utils
14from autotest_lib.client.common_lib import error
15
16
17def CheckInterfaceForDestination(host, expected_interface,
18                                 family=socket.AF_UNSPEC):
19    """
20    Checks that routes for host go through a given interface.
21
22    The concern here is that our network setup may have gone wrong
23    and our test connections may go over some other network than
24    the one we're trying to test.  So we take all the IP addresses
25    for the supplied host and make sure they go through the given
26    network interface.
27
28    @param host: Destination host
29    @param expected_interface: Expected interface name
30    @raises: error.TestFail if the routes for the given host go through
31            a different interface than the expected one.
32
33    """
34    def _MatchesRoute(address, expected_interface):
35        """
36        Returns whether or not |expected_interface| is used to reach |address|.
37
38        @param address: string containing an IP (v4 or v6) address.
39        @param expected_interface: string containing an interface name.
40
41        """
42        output = utils.run('ip route get %s' % address).stdout
43
44        if re.search(r'unreachable', output):
45            return False
46
47        match = re.search(r'\sdev\s(\S+)', output)
48        if match is None:
49            return False
50        interface = match.group(1)
51
52        logging.info('interface for %s: %s', address, interface)
53        if interface != expected_interface:
54            raise error.TestFail('Target server %s uses interface %s'
55                                 '(%s expected).' %
56                                 (address, interface, expected_interface))
57        return True
58
59    # addrinfo records: (family, type, proto, canonname, (addr, port))
60    server_addresses = [record[4][0]
61                        for record in socket.getaddrinfo(host, 80, family)]
62    for address in server_addresses:
63        # Routes may not always be up by this point. Note that routes for v4 or
64        # v6 may come up before the other, so we simply do this poll for all
65        # addresses.
66        utils.poll_for_condition(
67            condition=lambda: _MatchesRoute(address, expected_interface),
68            exception=error.TestFail('No route to %s' % address),
69            timeout=1)
70
71FETCH_URL_PATTERN_FOR_TEST = \
72    'http://testing-chargen.appspot.com/download?size=%d'
73
74def FetchUrl(url_pattern, bytes_to_fetch=10, fetch_timeout=10):
75    """
76    Fetches a specified number of bytes from a URL.
77
78    @param url_pattern: URL pattern for fetching a specified number of bytes.
79            %d in the pattern is to be filled in with the number of bytes to
80            fetch.
81    @param bytes_to_fetch: Number of bytes to fetch.
82    @param fetch_timeout: Number of seconds to wait for the fetch to complete
83            before it times out.
84    @return: The time in seconds spent for fetching the specified number of
85            bytes.
86    @raises: error.TestError if one of the following happens:
87            - The fetch takes no time.
88            - The number of bytes fetched differs from the specified
89              number.
90
91    """
92    # Limit the amount of bytes to read at a time.
93    _MAX_FETCH_READ_BYTES = 1024 * 1024
94
95    url = url_pattern % bytes_to_fetch
96    logging.info('FetchUrl %s', url)
97    start_time = time.time()
98    result = urllib2.urlopen(url, timeout=fetch_timeout)
99    bytes_fetched = 0
100    while bytes_fetched < bytes_to_fetch:
101        bytes_left = bytes_to_fetch - bytes_fetched
102        bytes_to_read = min(bytes_left, _MAX_FETCH_READ_BYTES)
103        bytes_read = len(result.read(bytes_to_read))
104        bytes_fetched += bytes_read
105        if bytes_read != bytes_to_read:
106            raise error.TestError('FetchUrl tried to read %d bytes, but got '
107                                  '%d bytes instead.' %
108                                  (bytes_to_read, bytes_read))
109        fetch_time = time.time() - start_time
110        if fetch_time > fetch_timeout:
111            raise error.TestError('FetchUrl exceeded timeout.')
112
113    return fetch_time
114