media/webrtc/trunk/build/android/pylib/ports.py

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

michael@0 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 # Use of this source code is governed by a BSD-style license that can be
michael@0 3 # found in the LICENSE file.
michael@0 4
michael@0 5 """Functions that deals with local and device ports."""
michael@0 6
michael@0 7 import contextlib
michael@0 8 import fcntl
michael@0 9 import httplib
michael@0 10 import logging
michael@0 11 import os
michael@0 12 import re
michael@0 13 import socket
michael@0 14 import traceback
michael@0 15
michael@0 16 import cmd_helper
michael@0 17 import constants
michael@0 18
michael@0 19
michael@0 20 #The following two methods are used to allocate the port source for various
michael@0 21 # types of test servers. Because some net relates tests can be run on shards
michael@0 22 # at same time, it's important to have a mechanism to allocate the port process
michael@0 23 # safe. In here, we implement the safe port allocation by leveraging flock.
michael@0 24 def ResetTestServerPortAllocation():
michael@0 25 """Reset the port allocation to start from TEST_SERVER_PORT_FIRST.
michael@0 26
michael@0 27 Returns:
michael@0 28 Returns True if reset successes. Otherwise returns False.
michael@0 29 """
michael@0 30 try:
michael@0 31 with open(constants.TEST_SERVER_PORT_FILE, 'w') as fp:
michael@0 32 fp.write('%d' % constants.TEST_SERVER_PORT_FIRST)
michael@0 33 if os.path.exists(constants.TEST_SERVER_PORT_LOCKFILE):
michael@0 34 os.unlink(constants.TEST_SERVER_PORT_LOCKFILE)
michael@0 35 return True
michael@0 36 except Exception as e:
michael@0 37 logging.error(e)
michael@0 38 return False
michael@0 39
michael@0 40
michael@0 41 def AllocateTestServerPort():
michael@0 42 """Allocate a port incrementally.
michael@0 43
michael@0 44 Returns:
michael@0 45 Returns a valid port which should be in between TEST_SERVER_PORT_FIRST and
michael@0 46 TEST_SERVER_PORT_LAST. Returning 0 means no more valid port can be used.
michael@0 47 """
michael@0 48 port = 0
michael@0 49 ports_tried = []
michael@0 50 try:
michael@0 51 fp_lock = open(constants.TEST_SERVER_PORT_LOCKFILE, 'w')
michael@0 52 fcntl.flock(fp_lock, fcntl.LOCK_EX)
michael@0 53 # Get current valid port and calculate next valid port.
michael@0 54 assert os.path.exists(constants.TEST_SERVER_PORT_FILE)
michael@0 55 with open(constants.TEST_SERVER_PORT_FILE, 'r+') as fp:
michael@0 56 port = int(fp.read())
michael@0 57 ports_tried.append(port)
michael@0 58 while IsHostPortUsed(port):
michael@0 59 port += 1
michael@0 60 ports_tried.append(port)
michael@0 61 if (port > constants.TEST_SERVER_PORT_LAST or
michael@0 62 port < constants.TEST_SERVER_PORT_FIRST):
michael@0 63 port = 0
michael@0 64 else:
michael@0 65 fp.seek(0, os.SEEK_SET)
michael@0 66 fp.write('%d' % (port + 1))
michael@0 67 except Exception as e:
michael@0 68 logging.info(e)
michael@0 69 finally:
michael@0 70 if fp_lock:
michael@0 71 fcntl.flock(fp_lock, fcntl.LOCK_UN)
michael@0 72 fp_lock.close()
michael@0 73 if port:
michael@0 74 logging.info('Allocate port %d for test server.', port)
michael@0 75 else:
michael@0 76 logging.error('Could not allocate port for test server. '
michael@0 77 'List of ports tried: %s', str(ports_tried))
michael@0 78 return port
michael@0 79
michael@0 80
michael@0 81 def IsHostPortUsed(host_port):
michael@0 82 """Checks whether the specified host port is used or not.
michael@0 83
michael@0 84 Uses -n -P to inhibit the conversion of host/port numbers to host/port names.
michael@0 85
michael@0 86 Args:
michael@0 87 host_port: Port on host we want to check.
michael@0 88
michael@0 89 Returns:
michael@0 90 True if the port on host is already used, otherwise returns False.
michael@0 91 """
michael@0 92 port_info = '(127\.0\.0\.1)|(localhost)\:%d' % host_port
michael@0 93 # TODO(jnd): Find a better way to filter the port.
michael@0 94 re_port = re.compile(port_info, re.MULTILINE)
michael@0 95 if re_port.findall(cmd_helper.GetCmdOutput(['lsof', '-nPi:%d' % host_port])):
michael@0 96 return True
michael@0 97 return False
michael@0 98
michael@0 99
michael@0 100 def IsDevicePortUsed(adb, device_port, state=''):
michael@0 101 """Checks whether the specified device port is used or not.
michael@0 102
michael@0 103 Args:
michael@0 104 adb: Instance of AndroidCommands for talking to the device.
michael@0 105 device_port: Port on device we want to check.
michael@0 106 state: String of the specified state. Default is empty string, which
michael@0 107 means any state.
michael@0 108
michael@0 109 Returns:
michael@0 110 True if the port on device is already used, otherwise returns False.
michael@0 111 """
michael@0 112 base_url = '127.0.0.1:%d' % device_port
michael@0 113 netstat_results = adb.RunShellCommand('netstat', log_result=False)
michael@0 114 for single_connect in netstat_results:
michael@0 115 # Column 3 is the local address which we want to check with.
michael@0 116 connect_results = single_connect.split()
michael@0 117 is_state_match = connect_results[5] == state if state else True
michael@0 118 if connect_results[3] == base_url and is_state_match:
michael@0 119 return True
michael@0 120 return False
michael@0 121
michael@0 122
michael@0 123 def IsHttpServerConnectable(host, port, tries=3, command='GET', path='/',
michael@0 124 expected_read='', timeout=2):
michael@0 125 """Checks whether the specified http server is ready to serve request or not.
michael@0 126
michael@0 127 Args:
michael@0 128 host: Host name of the HTTP server.
michael@0 129 port: Port number of the HTTP server.
michael@0 130 tries: How many times we want to test the connection. The default value is
michael@0 131 3.
michael@0 132 command: The http command we use to connect to HTTP server. The default
michael@0 133 command is 'GET'.
michael@0 134 path: The path we use when connecting to HTTP server. The default path is
michael@0 135 '/'.
michael@0 136 expected_read: The content we expect to read from the response. The default
michael@0 137 value is ''.
michael@0 138 timeout: Timeout (in seconds) for each http connection. The default is 2s.
michael@0 139
michael@0 140 Returns:
michael@0 141 Tuple of (connect status, client error). connect status is a boolean value
michael@0 142 to indicate whether the server is connectable. client_error is the error
michael@0 143 message the server returns when connect status is false.
michael@0 144 """
michael@0 145 assert tries >= 1
michael@0 146 for i in xrange(0, tries):
michael@0 147 client_error = None
michael@0 148 try:
michael@0 149 with contextlib.closing(httplib.HTTPConnection(
michael@0 150 host, port, timeout=timeout)) as http:
michael@0 151 # Output some debug information when we have tried more than 2 times.
michael@0 152 http.set_debuglevel(i >= 2)
michael@0 153 http.request(command, path)
michael@0 154 r = http.getresponse()
michael@0 155 content = r.read()
michael@0 156 if r.status == 200 and r.reason == 'OK' and content == expected_read:
michael@0 157 return (True, '')
michael@0 158 client_error = ('Bad response: %s %s version %s\n ' %
michael@0 159 (r.status, r.reason, r.version) +
michael@0 160 '\n '.join([': '.join(h) for h in r.getheaders()]))
michael@0 161 except (httplib.HTTPException, socket.error) as e:
michael@0 162 # Probably too quick connecting: try again.
michael@0 163 exception_error_msgs = traceback.format_exception_only(type(e), e)
michael@0 164 if exception_error_msgs:
michael@0 165 client_error = ''.join(exception_error_msgs)
michael@0 166 # Only returns last client_error.
michael@0 167 return (False, client_error or 'Timeout')

mercurial