Upload upstream chrome fixes for python3

Make sure we get the latest changes from the catapult / telemetry
tsproxy version[1].

[1] https://source.chromium.org/chromium/chromium/src/+/main:third_party/crossbench/crossbench/network/traffic_shaping/ts_proxy.p

Change-Id: I550f94f874d92a77c4f3f71bfd99efe0f5ef3684
diff --git a/tsproxy.py b/tsproxy.py
index 52c73d3..22be644 100644
--- a/tsproxy.py
+++ b/tsproxy.py
@@ -48,7 +48,13 @@
 REMOVE_TCP_OVERHEAD = 1460.0 / 1500.0
 lock = threading.Lock()
 background_activity_count = 0
-current_time = time.clock if sys.platform == "win32" else time.time
+if sys.platform == "win32":
+  try:
+    current_time = time.perf_counter
+  except AttributeError:
+    current_time = time.clock
+else:
+  current_time = time.time
 try:
   import monotonic
   current_time = monotonic.monotonic
@@ -56,6 +62,23 @@
   pass
 
 
+if sys.version_info.major == 3:
+  # In Python 2, data from/to the socket are stored in character strings,
+  # and the built-in ord() and chr() functions are used to convert between
+  # characters and integers.
+  #
+  # In Python 3, data are stored in bytes, and we need to redefine ord and
+  # chr functions to make it work.
+
+  def ord(x):
+    # In Python 3, indexing a byte string returns an int, no conversion needed.
+    return x
+
+  def chr(x):
+    # Convert a byte into bytes of length 1.
+    return bytes([x])
+
+
 def PrintMessage(msg):
   # Print the message to stdout & flush to make sure that the message is not
   # buffered when tsproxy is run as a subprocess.
@@ -234,7 +257,7 @@
     asyncore.dispatcher.__init__(self)
     self.client_id = client_id
     self.state = self.STATE_IDLE
-    self.buffer = ''
+    self.buffer = b''
     self.addr = None
     self.dns_thread = None
     self.hostname = None
@@ -336,9 +359,9 @@
     if 'port' in message:
       self.port = message['port']
     logging.info('[{0:d}] Resolving {1}:{2:d}'.format(self.client_id, self.hostname, self.port))
-    if self.hostname == 'localhost':
-      self.hostname = '127.0.0.1'
-    if self.hostname == '127.0.0.1':
+    if self.hostname == b'localhost':
+      self.hostname = b'127.0.0.1'
+    if self.hostname == b'127.0.0.1':
       logging.info('[{0:d}] Connection to localhost detected'.format(self.client_id))
       is_localhost = True
     if (dest_addresses is not None) and (not is_localhost or map_localhost):
@@ -427,7 +450,7 @@
     self.hostname = None
     self.port = None
     self.requested_address = None
-    self.buffer = ''
+    self.buffer = b''
     self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
     self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 128 * 1024)
     self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 128 * 1024)
@@ -686,7 +709,7 @@
   global REMOVE_TCP_OVERHEAD
   parser = argparse.ArgumentParser(description='Traffic-shaping socks5 proxy.',
                                    prog='tsproxy')
-  parser.add_argument('-v', '--verbose', action='count', help="Increase verbosity (specify multiple times for more). -vvvv for full debug output.")
+  parser.add_argument('-v', '--verbose', action='count', default=0, help="Increase verbosity (specify multiple times for more). -vvvv for full debug output.")
   parser.add_argument('--logfile', help="Write log messages to given file instead of stdout.")
   parser.add_argument('-b', '--bind', default='localhost', help="Server interface address (defaults to localhost).")
   parser.add_argument('-p', '--port', type=int, default=1080, help="Server port (defaults to 1080, use 0 for randomly assigned).")