Collect stats to investigate the viability of UDP
connectivity from the browser (first cut). Collect
stats for TCP connectivity also.

- What percentage of users can get a message end-to-end
  to an TCP and UDP server.
- What is the latency for TCP and UDP messages.

Added TCP and UDP echo servers to testserver.py
for unittests.

BUG=82565
TEST=udp tests
Review URL: http://codereview.chromium.org/7056031

git-svn-id: http://src.chromium.org/svn/trunk/src/net/tools/testserver@88495 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/testserver.py b/testserver.py
index c8fab2b..693b50b 100755
--- a/testserver.py
+++ b/testserver.py
@@ -3,7 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""This is a simple HTTP server used for testing Chrome.
+"""This is a simple HTTP/FTP/SYNC/TCP ECHO/UDP ECHO/ server used for testing
+Chrome.
 
 It supports several test URLs, as specified by the handlers in TestPageHandler.
 By default, it listens on an ephemeral port and sends the port number back to
@@ -52,6 +53,8 @@
 SERVER_HTTP = 0
 SERVER_FTP = 1
 SERVER_SYNC = 2
+SERVER_TCP_ECHO = 3
+SERVER_UDP_ECHO = 4
 
 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 .
 debug_output = sys.stderr
@@ -209,6 +212,42 @@
                          asyncore.dispatcher.handle_expt_event)
 
 
+class TCPEchoServer(SocketServer.TCPServer):
+  """A TCP echo server that echoes back what it has received."""
+
+  def server_bind(self):
+    """Override server_bind to store the server name."""
+    SocketServer.TCPServer.server_bind(self)
+    host, port = self.socket.getsockname()[:2]
+    self.server_name = socket.getfqdn(host)
+    self.server_port = port
+
+  def serve_forever(self):
+    self.stop = False
+    self.nonce_time = None
+    while not self.stop:
+      self.handle_request()
+    self.socket.close()
+
+
+class UDPEchoServer(SocketServer.UDPServer):
+  """A UDP echo server that echoes back what it has received."""
+
+  def server_bind(self):
+    """Override server_bind to store the server name."""
+    SocketServer.UDPServer.server_bind(self)
+    host, port = self.socket.getsockname()[:2]
+    self.server_name = socket.getfqdn(host)
+    self.server_port = port
+
+  def serve_forever(self):
+    self.stop = False
+    self.nonce_time = None
+    while not self.stop:
+      self.handle_request()
+    self.socket.close()
+
+
 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
 
   def __init__(self, request, client_address, socket_server,
@@ -1446,6 +1485,34 @@
 
   return my_data_dir
 
+
+class TCPEchoHandler(SocketServer.BaseRequestHandler):
+  """The RequestHandler class for TCP echo server.
+
+  It is instantiated once per connection to the server, and overrides the
+  handle() method to implement communication to the client.
+  """
+
+  def handle(self):
+    data = self.request.recv(65536)
+    if not data:
+        return
+    self.request.send(data)
+
+
+class UDPEchoHandler(SocketServer.BaseRequestHandler):
+  """The RequestHandler class for UDP echo server.
+
+  It is instantiated once per connection to the server, and overrides the
+  handle() method to implement communication to the client.
+  """
+
+  def handle(self):
+    data = self.request[0].strip()
+    socket = self.request[1]
+    socket.sendto(data, self.client_address)
+
+
 class FileMultiplexer:
   def __init__(self, fd1, fd2) :
     self.__fd1 = fd1
@@ -1509,6 +1576,14 @@
     print 'Sync XMPP server started on port %d...' % server.xmpp_port
     server_data['port'] = server.server_port
     server_data['xmpp_port'] = server.xmpp_port
+  elif options.server_type == SERVER_TCP_ECHO:
+    server = TCPEchoServer(('127.0.0.1', port), TCPEchoHandler)
+    print 'Echo TCP server started on port %d...' % server.server_port
+    server_data['port'] = server.server_port
+  elif options.server_type == SERVER_UDP_ECHO:
+    server = UDPEchoServer(('127.0.0.1', port), UDPEchoHandler)
+    print 'Echo UDP server started on port %d...' % server.server_port
+    server_data['port'] = server.server_port
   # means FTP Server
   else:
     my_data_dir = MakeDataDir()
@@ -1571,6 +1646,14 @@
                            const=SERVER_SYNC, default=SERVER_HTTP,
                            dest='server_type',
                            help='start up a sync server.')
+  option_parser.add_option('', '--tcp-echo', action='store_const',
+                           const=SERVER_TCP_ECHO, default=SERVER_HTTP,
+                           dest='server_type',
+                           help='start up a tcp echo server.')
+  option_parser.add_option('', '--udp-echo', action='store_const',
+                           const=SERVER_UDP_ECHO, default=SERVER_HTTP,
+                           dest='server_type',
+                           help='start up a udp echo server.')
   option_parser.add_option('', '--log-to-console', action='store_const',
                            const=True, default=False,
                            dest='log_to_console',