OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Functions that deals with local and device ports.""" | 5 """Functions that deal with local and device ports.""" |
6 | 6 |
7 import contextlib | 7 import contextlib |
8 import fcntl | 8 import fcntl |
9 import httplib | 9 import httplib |
10 import logging | 10 import logging |
11 import os | 11 import os |
12 import re | 12 import re |
13 import socket | 13 import socket |
14 import traceback | 14 import traceback |
15 | 15 |
16 import cmd_helper | 16 import cmd_helper |
17 import constants | 17 import constants |
18 | 18 |
19 | 19 |
20 #The following two methods are used to allocate the port source for various | 20 # The following two methods are used to allocate the port source for various |
21 # types of test servers. Because some net relates tests can be run on shards | 21 # types of test servers. Because some net-related tests can be run on shards at |
22 # at same time, it's important to have a mechanism to allocate the port process | 22 # same time, it's important to have a mechanism to allocate the port |
23 # safe. In here, we implement the safe port allocation by leveraging flock. | 23 # process-safe. In here, we implement the safe port allocation by leveraging |
| 24 # flock. |
24 def ResetTestServerPortAllocation(): | 25 def ResetTestServerPortAllocation(): |
25 """Reset the port allocation to start from TEST_SERVER_PORT_FIRST. | 26 """Resets the port allocation to start from TEST_SERVER_PORT_FIRST. |
26 | 27 |
27 Returns: | 28 Returns: |
28 Returns True if reset successes. Otherwise returns False. | 29 Returns True if reset successes. Otherwise returns False. |
29 """ | 30 """ |
30 try: | 31 try: |
31 with open(constants.TEST_SERVER_PORT_FILE, 'w') as fp: | 32 with open(constants.TEST_SERVER_PORT_FILE, 'w') as fp: |
32 fp.write('%d' % constants.TEST_SERVER_PORT_FIRST) | 33 fp.write('%d' % constants.TEST_SERVER_PORT_FIRST) |
33 if os.path.exists(constants.TEST_SERVER_PORT_LOCKFILE): | 34 if os.path.exists(constants.TEST_SERVER_PORT_LOCKFILE): |
34 os.unlink(constants.TEST_SERVER_PORT_LOCKFILE) | 35 os.unlink(constants.TEST_SERVER_PORT_LOCKFILE) |
35 return True | 36 return True |
36 except Exception as e: | 37 except Exception as e: |
37 logging.error(e) | 38 logging.error(e) |
38 return False | 39 return False |
39 | 40 |
40 | 41 |
41 def AllocateTestServerPort(): | 42 def AllocateTestServerPort(): |
42 """Allocate a port incrementally. | 43 """Allocates a port incrementally. |
43 | 44 |
44 Returns: | 45 Returns: |
45 Returns a valid port which should be in between TEST_SERVER_PORT_FIRST and | 46 Returns a valid port which should be in between TEST_SERVER_PORT_FIRST and |
46 TEST_SERVER_PORT_LAST. Returning 0 means no more valid port can be used. | 47 TEST_SERVER_PORT_LAST. Returning 0 means no more valid port can be used. |
47 """ | 48 """ |
48 port = 0 | 49 port = 0 |
49 ports_tried = [] | 50 ports_tried = [] |
50 try: | 51 try: |
51 fp_lock = open(constants.TEST_SERVER_PORT_LOCKFILE, 'w') | 52 fp_lock = open(constants.TEST_SERVER_PORT_LOCKFILE, 'w') |
52 fcntl.flock(fp_lock, fcntl.LOCK_EX) | 53 fcntl.flock(fp_lock, fcntl.LOCK_EX) |
(...skipping 30 matching lines...) Expand all Loading... |
83 """Checks whether the specified host port is used or not. | 84 """Checks whether the specified host port is used or not. |
84 | 85 |
85 Uses -n -P to inhibit the conversion of host/port numbers to host/port names. | 86 Uses -n -P to inhibit the conversion of host/port numbers to host/port names. |
86 | 87 |
87 Args: | 88 Args: |
88 host_port: Port on host we want to check. | 89 host_port: Port on host we want to check. |
89 | 90 |
90 Returns: | 91 Returns: |
91 True if the port on host is already used, otherwise returns False. | 92 True if the port on host is already used, otherwise returns False. |
92 """ | 93 """ |
93 port_info = '(127\.0\.0\.1)|(localhost)\:%d' % host_port | 94 port_info = '(\*)|(127\.0\.0\.1)|(localhost):%d' % host_port |
94 # TODO(jnd): Find a better way to filter the port. | 95 # TODO(jnd): Find a better way to filter the port. Note that connecting to the |
| 96 # socket and closing it would leave it in the TIME_WAIT state. Setting |
| 97 # SO_LINGER on it and then closing it makes the Python HTTP server crash. |
95 re_port = re.compile(port_info, re.MULTILINE) | 98 re_port = re.compile(port_info, re.MULTILINE) |
96 if re_port.findall(cmd_helper.GetCmdOutput(['lsof', '-nPi:%d' % host_port])): | 99 if re_port.search(cmd_helper.GetCmdOutput(['lsof', '-nPi:%d' % host_port])): |
97 return True | 100 return True |
98 return False | 101 return False |
99 | 102 |
100 | 103 |
101 def IsDevicePortUsed(adb, device_port, state=''): | 104 def IsDevicePortUsed(adb, device_port, state=''): |
102 """Checks whether the specified device port is used or not. | 105 """Checks whether the specified device port is used or not. |
103 | 106 |
104 Args: | 107 Args: |
105 adb: Instance of AndroidCommands for talking to the device. | 108 adb: Instance of AndroidCommands for talking to the device. |
106 device_port: Port on device we want to check. | 109 device_port: Port on device we want to check. |
107 state: String of the specified state. Default is empty string, which | 110 state: String of the specified state. Default is empty string, which |
108 means any state. | 111 means any state. |
109 | 112 |
110 Returns: | 113 Returns: |
111 True if the port on device is already used, otherwise returns False. | 114 True if the port on device is already used, otherwise returns False. |
112 """ | 115 """ |
113 base_url = '127.0.0.1:%d' % device_port | 116 base_url = '127.0.0.1:%d' % device_port |
114 netstat_results = adb.RunShellCommand('netstat', log_result=False) | 117 netstat_results = adb.RunShellCommand('netstat', log_result=False) |
115 for single_connect in netstat_results: | 118 for single_connect in netstat_results: |
116 # Column 3 is the local address which we want to check with. | 119 # Column 3 is the local address which we want to check with. |
117 connect_results = single_connect.split() | 120 connect_results = single_connect.split() |
| 121 if connect_results[0] != 'tcp': |
| 122 continue |
| 123 if len(connect_results) < 6: |
| 124 raise Exception('Unexpected format while parsing netstat line: ' + |
| 125 single_connect) |
118 is_state_match = connect_results[5] == state if state else True | 126 is_state_match = connect_results[5] == state if state else True |
119 if connect_results[3] == base_url and is_state_match: | 127 if connect_results[3] == base_url and is_state_match: |
120 return True | 128 return True |
121 return False | 129 return False |
122 | 130 |
123 | 131 |
124 def IsHttpServerConnectable(host, port, tries=3, command='GET', path='/', | 132 def IsHttpServerConnectable(host, port, tries=3, command='GET', path='/', |
125 expected_read='', timeout=2): | 133 expected_read='', timeout=2): |
126 """Checks whether the specified http server is ready to serve request or not. | 134 """Checks whether the specified http server is ready to serve request or not. |
127 | 135 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 client_error = ('Bad response: %s %s version %s\n ' % | 167 client_error = ('Bad response: %s %s version %s\n ' % |
160 (r.status, r.reason, r.version) + | 168 (r.status, r.reason, r.version) + |
161 '\n '.join([': '.join(h) for h in r.getheaders()])) | 169 '\n '.join([': '.join(h) for h in r.getheaders()])) |
162 except (httplib.HTTPException, socket.error) as e: | 170 except (httplib.HTTPException, socket.error) as e: |
163 # Probably too quick connecting: try again. | 171 # Probably too quick connecting: try again. |
164 exception_error_msgs = traceback.format_exception_only(type(e), e) | 172 exception_error_msgs = traceback.format_exception_only(type(e), e) |
165 if exception_error_msgs: | 173 if exception_error_msgs: |
166 client_error = ''.join(exception_error_msgs) | 174 client_error = ''.join(exception_error_msgs) |
167 # Only returns last client_error. | 175 # Only returns last client_error. |
168 return (False, client_error or 'Timeout') | 176 return (False, client_error or 'Timeout') |
OLD | NEW |