Upgrade to 3.29

Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.

Bug: 17370214

Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/tools/testrunner/server/__init__.py b/tools/testrunner/server/__init__.py
new file mode 100644
index 0000000..202a262
--- /dev/null
+++ b/tools/testrunner/server/__init__.py
@@ -0,0 +1,26 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tools/testrunner/server/compression.py b/tools/testrunner/server/compression.py
new file mode 100644
index 0000000..d5ed415
--- /dev/null
+++ b/tools/testrunner/server/compression.py
@@ -0,0 +1,111 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import cStringIO as StringIO
+try:
+  import ujson as json
+except ImportError:
+  import json
+import os
+import struct
+import zlib
+
+from . import constants
+
+def Send(obj, sock):
+  """
+  Sends a JSON encodable object over the specified socket (zlib-compressed).
+  """
+  obj = json.dumps(obj)
+  compression_level = 2  # 1 = fastest, 9 = best compression
+  compressed = zlib.compress(obj, compression_level)
+  payload = struct.pack('>i', len(compressed)) + compressed
+  sock.sendall(payload)
+
+
+class Receiver(object):
+  def __init__(self, sock):
+    self.sock = sock
+    self.data = StringIO.StringIO()
+    self.datalength = 0
+    self._next = self._GetNext()
+
+  def IsDone(self):
+    return self._next == None
+
+  def Current(self):
+    return self._next
+
+  def Advance(self):
+    try:
+      self._next = self._GetNext()
+    except:
+      raise
+
+  def _GetNext(self):
+    try:
+      while self.datalength < constants.SIZE_T:
+        try:
+          chunk = self.sock.recv(8192)
+        except:
+          raise
+        if not chunk: return None
+        self._AppendData(chunk)
+      size = self._PopData(constants.SIZE_T)
+      size = struct.unpack(">i", size)[0]
+      while self.datalength < size:
+        try:
+          chunk = self.sock.recv(8192)
+        except:
+          raise
+        if not chunk: return None
+        self._AppendData(chunk)
+      result = self._PopData(size)
+      result = zlib.decompress(result)
+      result = json.loads(result)
+      if result == constants.END_OF_STREAM:
+        return None
+      return result
+    except:
+      raise
+
+  def _AppendData(self, new):
+    self.data.seek(0, os.SEEK_END)
+    self.data.write(new)
+    self.datalength += len(new)
+
+  def _PopData(self, length):
+    self.data.seek(0)
+    chunk = self.data.read(length)
+    remaining = self.data.read()
+    self.data.close()
+    self.data = StringIO.StringIO()
+    self.data.write(remaining)
+    assert self.datalength - length == len(remaining)
+    self.datalength = len(remaining)
+    return chunk
diff --git a/tools/testrunner/server/constants.py b/tools/testrunner/server/constants.py
new file mode 100644
index 0000000..5aefcba
--- /dev/null
+++ b/tools/testrunner/server/constants.py
@@ -0,0 +1,51 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+CLIENT_PORT = 9991  # Port for the local client to connect to.
+PEER_PORT = 9992  # Port for peers on the network to connect to.
+PRESENCE_PORT = 9993  # Port for presence daemon.
+STATUS_PORT = 9994  # Port for network requests not related to workpackets.
+
+END_OF_STREAM = "end of dtest stream"  # Marker for end of network requests.
+SIZE_T = 4  # Number of bytes used for network request size header.
+
+# Messages understood by the local request handler.
+ADD_TRUSTED = "add trusted"
+INFORM_DURATION = "inform about duration"
+REQUEST_PEERS = "get peers"
+UNRESPONSIVE_PEER = "unresponsive peer"
+REQUEST_PUBKEY_FINGERPRINT = "get pubkey fingerprint"
+REQUEST_STATUS = "get status"
+UPDATE_PERF = "update performance"
+
+# Messages understood by the status request handler.
+LIST_TRUSTED_PUBKEYS = "list trusted pubkeys"
+GET_SIGNED_PUBKEY = "pass on signed pubkey"
+NOTIFY_NEW_TRUSTED = "new trusted peer"
+TRUST_YOU_NOW = "trust you now"
+DO_YOU_TRUST = "do you trust"
diff --git a/tools/testrunner/server/daemon.py b/tools/testrunner/server/daemon.py
new file mode 100644
index 0000000..baa66fb
--- /dev/null
+++ b/tools/testrunner/server/daemon.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+
+# This code has been written by Sander Marechal and published at:
+# http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
+# where the author has placed it in the public domain (see comment #6 at
+# http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/#c6
+# ).
+# Some minor modifications have been made by the V8 authors. The work remains
+# in the public domain.
+
+import atexit
+import os
+from signal import SIGTERM
+from signal import SIGINT
+import sys
+import time
+
+
+class Daemon(object):
+  """
+  A generic daemon class.
+
+  Usage: subclass the Daemon class and override the run() method
+  """
+  def __init__(self, pidfile, stdin='/dev/null',
+               stdout='/dev/null', stderr='/dev/null'):
+    self.stdin = stdin
+    self.stdout = stdout
+    self.stderr = stderr
+    self.pidfile = pidfile
+
+  def daemonize(self):
+    """
+    do the UNIX double-fork magic, see Stevens' "Advanced
+    Programming in the UNIX Environment" for details (ISBN 0201563177)
+    http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
+    """
+    try:
+      pid = os.fork()
+      if pid > 0:
+        # exit first parent
+        sys.exit(0)
+    except OSError, e:
+      sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
+      sys.exit(1)
+
+    # decouple from parent environment
+    os.chdir("/")
+    os.setsid()
+    os.umask(0)
+
+    # do second fork
+    try:
+      pid = os.fork()
+      if pid > 0:
+        # exit from second parent
+        sys.exit(0)
+    except OSError, e:
+      sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
+      sys.exit(1)
+
+    # redirect standard file descriptors
+    sys.stdout.flush()
+    sys.stderr.flush()
+    si = file(self.stdin, 'r')
+    so = file(self.stdout, 'a+')
+    se = file(self.stderr, 'a+', 0)
+    # TODO: (debug) re-enable this!
+    #os.dup2(si.fileno(), sys.stdin.fileno())
+    #os.dup2(so.fileno(), sys.stdout.fileno())
+    #os.dup2(se.fileno(), sys.stderr.fileno())
+
+    # write pidfile
+    atexit.register(self.delpid)
+    pid = str(os.getpid())
+    file(self.pidfile, 'w+').write("%s\n" % pid)
+
+  def delpid(self):
+    os.remove(self.pidfile)
+
+  def start(self):
+    """
+    Start the daemon
+    """
+    # Check for a pidfile to see if the daemon already runs
+    try:
+      pf = file(self.pidfile, 'r')
+      pid = int(pf.read().strip())
+      pf.close()
+    except IOError:
+      pid = None
+
+    if pid:
+      message = "pidfile %s already exist. Daemon already running?\n"
+      sys.stderr.write(message % self.pidfile)
+      sys.exit(1)
+
+    # Start the daemon
+    self.daemonize()
+    self.run()
+
+  def stop(self):
+    """
+    Stop the daemon
+    """
+    # Get the pid from the pidfile
+    try:
+      pf = file(self.pidfile, 'r')
+      pid = int(pf.read().strip())
+      pf.close()
+    except IOError:
+      pid = None
+
+    if not pid:
+      message = "pidfile %s does not exist. Daemon not running?\n"
+      sys.stderr.write(message % self.pidfile)
+      return # not an error in a restart
+
+    # Try killing the daemon process
+    try:
+      # Give the process a one-second chance to exit gracefully.
+      os.kill(pid, SIGINT)
+      time.sleep(1)
+      while 1:
+        os.kill(pid, SIGTERM)
+        time.sleep(0.1)
+    except OSError, err:
+      err = str(err)
+      if err.find("No such process") > 0:
+        if os.path.exists(self.pidfile):
+          os.remove(self.pidfile)
+      else:
+        print str(err)
+        sys.exit(1)
+
+  def restart(self):
+    """
+    Restart the daemon
+    """
+    self.stop()
+    self.start()
+
+  def run(self):
+    """
+    You should override this method when you subclass Daemon. It will be
+    called after the process has been daemonized by start() or restart().
+    """
diff --git a/tools/testrunner/server/local_handler.py b/tools/testrunner/server/local_handler.py
new file mode 100644
index 0000000..3b3ac49
--- /dev/null
+++ b/tools/testrunner/server/local_handler.py
@@ -0,0 +1,119 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import socket
+import SocketServer
+import StringIO
+
+from . import compression
+from . import constants
+
+
+def LocalQuery(query):
+  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+  code = sock.connect_ex(("localhost", constants.CLIENT_PORT))
+  if code != 0: return None
+  compression.Send(query, sock)
+  compression.Send(constants.END_OF_STREAM, sock)
+  rec = compression.Receiver(sock)
+  data = None
+  while not rec.IsDone():
+    data = rec.Current()
+    assert data[0] == query[0]
+    data = data[1]
+    rec.Advance()
+  sock.close()
+  return data
+
+
+class LocalHandler(SocketServer.BaseRequestHandler):
+  def handle(self):
+    rec = compression.Receiver(self.request)
+    while not rec.IsDone():
+      data = rec.Current()
+      action = data[0]
+
+      if action == constants.REQUEST_PEERS:
+        with self.server.daemon.peer_list_lock:
+          response = [ p.Pack() for p in self.server.daemon.peers
+                       if p.trusting_me ]
+        compression.Send([action, response], self.request)
+
+      elif action == constants.UNRESPONSIVE_PEER:
+        self.server.daemon.DeletePeer(data[1])
+
+      elif action == constants.REQUEST_PUBKEY_FINGERPRINT:
+        compression.Send([action, self.server.daemon.pubkey_fingerprint],
+                         self.request)
+
+      elif action == constants.REQUEST_STATUS:
+        compression.Send([action, self._GetStatusMessage()], self.request)
+
+      elif action == constants.ADD_TRUSTED:
+        fingerprint = self.server.daemon.CopyToTrusted(data[1])
+        compression.Send([action, fingerprint], self.request)
+
+      elif action == constants.INFORM_DURATION:
+        test_key = data[1]
+        test_duration = data[2]
+        arch = data[3]
+        mode = data[4]
+        self.server.daemon.AddPerfData(test_key, test_duration, arch, mode)
+
+      elif action == constants.UPDATE_PERF:
+        address = data[1]
+        perf = data[2]
+        self.server.daemon.UpdatePeerPerformance(data[1], data[2])
+
+      rec.Advance()
+    compression.Send(constants.END_OF_STREAM, self.request)
+
+  def _GetStatusMessage(self):
+    sio = StringIO.StringIO()
+    sio.write("Peers:\n")
+    with self.server.daemon.peer_list_lock:
+      for p in self.server.daemon.peers:
+        sio.write("%s\n" % p)
+    sio.write("My own jobs: %d, relative performance: %.2f\n" %
+              (self.server.daemon.jobs, self.server.daemon.relative_perf))
+    # Low-priority TODO: Return more information. Ideas:
+    #   - currently running anything,
+    #   - time since last job,
+    #   - time since last repository fetch
+    #   - number of workpackets/testcases handled since startup
+    #   - slowest test(s)
+    result = sio.getvalue()
+    sio.close()
+    return result
+
+
+class LocalSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
+  def __init__(self, daemon):
+    SocketServer.TCPServer.__init__(self, ("localhost", constants.CLIENT_PORT),
+                                    LocalHandler)
+    self.daemon = daemon
diff --git a/tools/testrunner/server/main.py b/tools/testrunner/server/main.py
new file mode 100644
index 0000000..1000713
--- /dev/null
+++ b/tools/testrunner/server/main.py
@@ -0,0 +1,245 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import multiprocessing
+import os
+import shutil
+import subprocess
+import threading
+import time
+
+from . import daemon
+from . import local_handler
+from . import presence_handler
+from . import signatures
+from . import status_handler
+from . import work_handler
+from ..network import perfdata
+
+
+class Server(daemon.Daemon):
+
+  def __init__(self, pidfile, root, stdin="/dev/null",
+               stdout="/dev/null", stderr="/dev/null"):
+    super(Server, self).__init__(pidfile, stdin, stdout, stderr)
+    self.root = root
+    self.local_handler = None
+    self.local_handler_thread = None
+    self.work_handler = None
+    self.work_handler_thread = None
+    self.status_handler = None
+    self.status_handler_thread = None
+    self.presence_daemon = None
+    self.presence_daemon_thread = None
+    self.peers = []
+    self.jobs = multiprocessing.cpu_count()
+    self.peer_list_lock = threading.Lock()
+    self.perf_data_lock = None
+    self.presence_daemon_lock = None
+    self.datadir = os.path.join(self.root, "data")
+    pubkey_fingerprint_filename = os.path.join(self.datadir, "mypubkey")
+    with open(pubkey_fingerprint_filename) as f:
+      self.pubkey_fingerprint = f.read().strip()
+    self.relative_perf_filename = os.path.join(self.datadir, "myperf")
+    if os.path.exists(self.relative_perf_filename):
+      with open(self.relative_perf_filename) as f:
+        try:
+          self.relative_perf = float(f.read())
+        except:
+          self.relative_perf = 1.0
+    else:
+      self.relative_perf = 1.0
+
+  def run(self):
+    os.nice(20)
+    self.ip = presence_handler.GetOwnIP()
+    self.perf_data_manager = perfdata.PerfDataManager(self.datadir)
+    self.perf_data_lock = threading.Lock()
+
+    self.local_handler = local_handler.LocalSocketServer(self)
+    self.local_handler_thread = threading.Thread(
+        target=self.local_handler.serve_forever)
+    self.local_handler_thread.start()
+
+    self.work_handler = work_handler.WorkSocketServer(self)
+    self.work_handler_thread = threading.Thread(
+        target=self.work_handler.serve_forever)
+    self.work_handler_thread.start()
+
+    self.status_handler = status_handler.StatusSocketServer(self)
+    self.status_handler_thread = threading.Thread(
+        target=self.status_handler.serve_forever)
+    self.status_handler_thread.start()
+
+    self.presence_daemon = presence_handler.PresenceDaemon(self)
+    self.presence_daemon_thread = threading.Thread(
+        target=self.presence_daemon.serve_forever)
+    self.presence_daemon_thread.start()
+
+    self.presence_daemon.FindPeers()
+    time.sleep(0.5)  # Give those peers some time to reply.
+
+    with self.peer_list_lock:
+      for p in self.peers:
+        if p.address == self.ip: continue
+        status_handler.RequestTrustedPubkeys(p, self)
+
+    while True:
+      try:
+        self.PeriodicTasks()
+        time.sleep(60)
+      except Exception, e:
+        print("MAIN LOOP EXCEPTION: %s" % e)
+        self.Shutdown()
+        break
+      except KeyboardInterrupt:
+        self.Shutdown()
+        break
+
+  def Shutdown(self):
+    with open(self.relative_perf_filename, "w") as f:
+      f.write("%s" % self.relative_perf)
+    self.presence_daemon.shutdown()
+    self.presence_daemon.server_close()
+    self.local_handler.shutdown()
+    self.local_handler.server_close()
+    self.work_handler.shutdown()
+    self.work_handler.server_close()
+    self.status_handler.shutdown()
+    self.status_handler.server_close()
+
+  def PeriodicTasks(self):
+    # If we know peers we don't trust, see if someone else trusts them.
+    with self.peer_list_lock:
+      for p in self.peers:
+        if p.trusted: continue
+        if self.IsTrusted(p.pubkey):
+          p.trusted = True
+          status_handler.ITrustYouNow(p)
+          continue
+        for p2 in self.peers:
+          if not p2.trusted: continue
+          status_handler.TryTransitiveTrust(p2, p.pubkey, self)
+    # TODO: Ping for more peers waiting to be discovered.
+    # TODO: Update the checkout (if currently idle).
+
+  def AddPeer(self, peer):
+    with self.peer_list_lock:
+      for p in self.peers:
+        if p.address == peer.address:
+          return
+      self.peers.append(peer)
+    if peer.trusted:
+      status_handler.ITrustYouNow(peer)
+
+  def DeletePeer(self, peer_address):
+    with self.peer_list_lock:
+      for i in xrange(len(self.peers)):
+        if self.peers[i].address == peer_address:
+          del self.peers[i]
+          return
+
+  def MarkPeerAsTrusting(self, peer_address):
+    with self.peer_list_lock:
+      for p in self.peers:
+        if p.address == peer_address:
+          p.trusting_me = True
+          break
+
+  def UpdatePeerPerformance(self, peer_address, performance):
+    with self.peer_list_lock:
+      for p in self.peers:
+        if p.address == peer_address:
+          p.relative_performance = performance
+
+  def CopyToTrusted(self, pubkey_filename):
+    with open(pubkey_filename, "r") as f:
+      lines = f.readlines()
+      fingerprint = lines[-1].strip()
+    target_filename = self._PubkeyFilename(fingerprint)
+    shutil.copy(pubkey_filename, target_filename)
+    with self.peer_list_lock:
+      for peer in self.peers:
+        if peer.address == self.ip: continue
+        if peer.pubkey == fingerprint:
+          status_handler.ITrustYouNow(peer)
+        else:
+          result = self.SignTrusted(fingerprint)
+          status_handler.NotifyNewTrusted(peer, result)
+    return fingerprint
+
+  def _PubkeyFilename(self, pubkey_fingerprint):
+    return os.path.join(self.root, "trusted", "%s.pem" % pubkey_fingerprint)
+
+  def IsTrusted(self, pubkey_fingerprint):
+    return os.path.exists(self._PubkeyFilename(pubkey_fingerprint))
+
+  def ListTrusted(self):
+    path = os.path.join(self.root, "trusted")
+    if not os.path.exists(path): return []
+    return [ f[:-4] for f in os.listdir(path) if f.endswith(".pem") ]
+
+  def SignTrusted(self, pubkey_fingerprint):
+    if not self.IsTrusted(pubkey_fingerprint):
+      return []
+    filename = self._PubkeyFilename(pubkey_fingerprint)
+    result = signatures.ReadFileAndSignature(filename)  # Format: [key, sig].
+    return [pubkey_fingerprint, result[0], result[1], self.pubkey_fingerprint]
+
+  def AcceptNewTrusted(self, data):
+    # The format of |data| matches the return value of |SignTrusted()|.
+    if not data: return
+    fingerprint = data[0]
+    pubkey = data[1]
+    signature = data[2]
+    signer = data[3]
+    if not self.IsTrusted(signer):
+      return
+    if self.IsTrusted(fingerprint):
+      return  # Already trust this guy.
+    filename = self._PubkeyFilename(fingerprint)
+    signer_pubkeyfile = self._PubkeyFilename(signer)
+    if not signatures.VerifySignature(filename, pubkey, signature,
+                                      signer_pubkeyfile):
+      return
+    return  # Nothing more to do.
+
+  def AddPerfData(self, test_key, duration, arch, mode):
+    data_store = self.perf_data_manager.GetStore(arch, mode)
+    data_store.RawUpdatePerfData(str(test_key), duration)
+
+  def CompareOwnPerf(self, test, arch, mode):
+    data_store = self.perf_data_manager.GetStore(arch, mode)
+    observed = data_store.FetchPerfData(test)
+    if not observed: return
+    own_perf_estimate = observed / test.duration
+    with self.perf_data_lock:
+      kLearnRateLimiter = 9999
+      self.relative_perf *= kLearnRateLimiter
+      self.relative_perf += own_perf_estimate
+      self.relative_perf /= (kLearnRateLimiter + 1)
diff --git a/tools/testrunner/server/presence_handler.py b/tools/testrunner/server/presence_handler.py
new file mode 100644
index 0000000..1dc2ef1
--- /dev/null
+++ b/tools/testrunner/server/presence_handler.py
@@ -0,0 +1,120 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import socket
+import SocketServer
+import threading
+try:
+  import ujson as json
+except:
+  import json
+
+from . import constants
+from ..objects import peer
+
+
+STARTUP_REQUEST = "V8 test peer starting up"
+STARTUP_RESPONSE = "Let's rock some tests!"
+EXIT_REQUEST = "V8 testing peer going down"
+
+
+def GetOwnIP():
+  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+  s.connect(("8.8.8.8", 80))
+  ip = s.getsockname()[0]
+  s.close()
+  return ip
+
+
+class PresenceHandler(SocketServer.BaseRequestHandler):
+
+  def handle(self):
+    data = json.loads(self.request[0].strip())
+
+    if data[0] == STARTUP_REQUEST:
+      jobs = data[1]
+      relative_perf = data[2]
+      pubkey_fingerprint = data[3]
+      trusted = self.server.daemon.IsTrusted(pubkey_fingerprint)
+      response = [STARTUP_RESPONSE, self.server.daemon.jobs,
+                  self.server.daemon.relative_perf,
+                  self.server.daemon.pubkey_fingerprint, trusted]
+      response = json.dumps(response)
+      self.server.SendTo(self.client_address[0], response)
+      p = peer.Peer(self.client_address[0], jobs, relative_perf,
+                    pubkey_fingerprint)
+      p.trusted = trusted
+      self.server.daemon.AddPeer(p)
+
+    elif data[0] == STARTUP_RESPONSE:
+      jobs = data[1]
+      perf = data[2]
+      pubkey_fingerprint = data[3]
+      p = peer.Peer(self.client_address[0], jobs, perf, pubkey_fingerprint)
+      p.trusted = self.server.daemon.IsTrusted(pubkey_fingerprint)
+      p.trusting_me = data[4]
+      self.server.daemon.AddPeer(p)
+
+    elif data[0] == EXIT_REQUEST:
+      self.server.daemon.DeletePeer(self.client_address[0])
+      if self.client_address[0] == self.server.daemon.ip:
+        self.server.shutdown_lock.release()
+
+
+class PresenceDaemon(SocketServer.ThreadingMixIn, SocketServer.UDPServer):
+  def __init__(self, daemon):
+    self.daemon = daemon
+    address = (daemon.ip, constants.PRESENCE_PORT)
+    SocketServer.UDPServer.__init__(self, address, PresenceHandler)
+    self.shutdown_lock = threading.Lock()
+
+  def shutdown(self):
+    self.shutdown_lock.acquire()
+    self.SendToAll(json.dumps([EXIT_REQUEST]))
+    self.shutdown_lock.acquire()
+    self.shutdown_lock.release()
+    SocketServer.UDPServer.shutdown(self)
+
+  def SendTo(self, target, message):
+    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+    sock.sendto(message, (target, constants.PRESENCE_PORT))
+    sock.close()
+
+  def SendToAll(self, message):
+    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+    ip = self.daemon.ip.split(".")
+    for i in range(1, 254):
+      ip[-1] = str(i)
+      sock.sendto(message, (".".join(ip), constants.PRESENCE_PORT))
+    sock.close()
+
+  def FindPeers(self):
+    request = [STARTUP_REQUEST, self.daemon.jobs, self.daemon.relative_perf,
+               self.daemon.pubkey_fingerprint]
+    request = json.dumps(request)
+    self.SendToAll(request)
diff --git a/tools/testrunner/server/signatures.py b/tools/testrunner/server/signatures.py
new file mode 100644
index 0000000..9957a18
--- /dev/null
+++ b/tools/testrunner/server/signatures.py
@@ -0,0 +1,63 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import base64
+import os
+import subprocess
+
+
+def ReadFileAndSignature(filename):
+  with open(filename, "rb") as f:
+    file_contents = base64.b64encode(f.read())
+  signature_file = filename + ".signature"
+  if (not os.path.exists(signature_file) or
+      os.path.getmtime(signature_file) < os.path.getmtime(filename)):
+    private_key = "~/.ssh/v8_dtest"
+    code = subprocess.call("openssl dgst -out %s -sign %s %s" %
+                           (signature_file, private_key, filename),
+                           shell=True)
+    if code != 0: return [None, code]
+  with open(signature_file) as f:
+    signature = base64.b64encode(f.read())
+  return [file_contents, signature]
+
+
+def VerifySignature(filename, file_contents, signature, pubkeyfile):
+  with open(filename, "wb") as f:
+    f.write(base64.b64decode(file_contents))
+  signature_file = filename + ".foreign_signature"
+  with open(signature_file, "wb") as f:
+    f.write(base64.b64decode(signature))
+  code = subprocess.call("openssl dgst -verify %s -signature %s %s" %
+                         (pubkeyfile, signature_file, filename),
+                         shell=True)
+  matched = (code == 0)
+  if not matched:
+    os.remove(signature_file)
+    os.remove(filename)
+  return matched
diff --git a/tools/testrunner/server/status_handler.py b/tools/testrunner/server/status_handler.py
new file mode 100644
index 0000000..3f2271d
--- /dev/null
+++ b/tools/testrunner/server/status_handler.py
@@ -0,0 +1,112 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import socket
+import SocketServer
+
+from . import compression
+from . import constants
+
+
+def _StatusQuery(peer, query):
+  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+  code = sock.connect_ex((peer.address, constants.STATUS_PORT))
+  if code != 0:
+    # TODO(jkummerow): disconnect (after 3 failures?)
+    return
+  compression.Send(query, sock)
+  compression.Send(constants.END_OF_STREAM, sock)
+  rec = compression.Receiver(sock)
+  data = None
+  while not rec.IsDone():
+    data = rec.Current()
+    assert data[0] == query[0]
+    data = data[1]
+    rec.Advance()
+  sock.close()
+  return data
+
+
+def RequestTrustedPubkeys(peer, server):
+  pubkey_list = _StatusQuery(peer, [constants.LIST_TRUSTED_PUBKEYS])
+  for pubkey in pubkey_list:
+    if server.IsTrusted(pubkey): continue
+    result = _StatusQuery(peer, [constants.GET_SIGNED_PUBKEY, pubkey])
+    server.AcceptNewTrusted(result)
+
+
+def NotifyNewTrusted(peer, data):
+  _StatusQuery(peer, [constants.NOTIFY_NEW_TRUSTED] + data)
+
+
+def ITrustYouNow(peer):
+  _StatusQuery(peer, [constants.TRUST_YOU_NOW])
+
+
+def TryTransitiveTrust(peer, pubkey, server):
+  if _StatusQuery(peer, [constants.DO_YOU_TRUST, pubkey]):
+    result = _StatusQuery(peer, [constants.GET_SIGNED_PUBKEY, pubkey])
+    server.AcceptNewTrusted(result)
+
+
+class StatusHandler(SocketServer.BaseRequestHandler):
+  def handle(self):
+    rec = compression.Receiver(self.request)
+    while not rec.IsDone():
+      data = rec.Current()
+      action = data[0]
+
+      if action == constants.LIST_TRUSTED_PUBKEYS:
+        response = self.server.daemon.ListTrusted()
+        compression.Send([action, response], self.request)
+
+      elif action == constants.GET_SIGNED_PUBKEY:
+        response = self.server.daemon.SignTrusted(data[1])
+        compression.Send([action, response], self.request)
+
+      elif action == constants.NOTIFY_NEW_TRUSTED:
+        self.server.daemon.AcceptNewTrusted(data[1:])
+        pass  # No response.
+
+      elif action == constants.TRUST_YOU_NOW:
+        self.server.daemon.MarkPeerAsTrusting(self.client_address[0])
+        pass  # No response.
+
+      elif action == constants.DO_YOU_TRUST:
+        response = self.server.daemon.IsTrusted(data[1])
+        compression.Send([action, response], self.request)
+
+      rec.Advance()
+    compression.Send(constants.END_OF_STREAM, self.request)
+
+
+class StatusSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
+  def __init__(self, daemon):
+    address = (daemon.ip, constants.STATUS_PORT)
+    SocketServer.TCPServer.__init__(self, address, StatusHandler)
+    self.daemon = daemon
diff --git a/tools/testrunner/server/work_handler.py b/tools/testrunner/server/work_handler.py
new file mode 100644
index 0000000..6bf7d43
--- /dev/null
+++ b/tools/testrunner/server/work_handler.py
@@ -0,0 +1,150 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import os
+import SocketServer
+import stat
+import subprocess
+import threading
+
+from . import compression
+from . import constants
+from . import signatures
+from ..network import endpoint
+from ..objects import workpacket
+
+
+class WorkHandler(SocketServer.BaseRequestHandler):
+
+  def handle(self):
+    rec = compression.Receiver(self.request)
+    while not rec.IsDone():
+      data = rec.Current()
+      with self.server.job_lock:
+        self._WorkOnWorkPacket(data)
+      rec.Advance()
+
+  def _WorkOnWorkPacket(self, data):
+    server_root = self.server.daemon.root
+    v8_root = os.path.join(server_root, "v8")
+    os.chdir(v8_root)
+    packet = workpacket.WorkPacket.Unpack(data)
+    self.ctx = packet.context
+    self.ctx.shell_dir = os.path.join("out",
+                                      "%s.%s" % (self.ctx.arch, self.ctx.mode))
+    if not os.path.isdir(self.ctx.shell_dir):
+      os.makedirs(self.ctx.shell_dir)
+    for binary in packet.binaries:
+      if not self._UnpackBinary(binary, packet.pubkey_fingerprint):
+        return
+
+    if not self._CheckoutRevision(packet.base_revision):
+      return
+
+    if not self._ApplyPatch(packet.patch):
+      return
+
+    tests = packet.tests
+    endpoint.Execute(v8_root, self.ctx, tests, self.request, self.server.daemon)
+    self._SendResponse()
+
+  def _SendResponse(self, error_message=None):
+    try:
+      if error_message:
+        compression.Send([[-1, error_message]], self.request)
+      compression.Send(constants.END_OF_STREAM, self.request)
+      return
+    except Exception, e:
+      pass  # Peer is gone. There's nothing we can do.
+    # Clean up.
+    self._Call("git checkout -f")
+    self._Call("git clean -f -d")
+    self._Call("rm -rf %s" % self.ctx.shell_dir)
+
+  def _UnpackBinary(self, binary, pubkey_fingerprint):
+    binary_name = binary["name"]
+    if binary_name == "libv8.so":
+      libdir = os.path.join(self.ctx.shell_dir, "lib.target")
+      if not os.path.exists(libdir): os.makedirs(libdir)
+      target = os.path.join(libdir, binary_name)
+    else:
+      target = os.path.join(self.ctx.shell_dir, binary_name)
+    pubkeyfile = "../trusted/%s.pem" % pubkey_fingerprint
+    if not signatures.VerifySignature(target, binary["blob"],
+                                      binary["sign"], pubkeyfile):
+      self._SendResponse("Signature verification failed")
+      return False
+    os.chmod(target, stat.S_IRWXU)
+    return True
+
+  def _CheckoutRevision(self, base_svn_revision):
+    get_hash_cmd = (
+        "git log -1 --format=%%H --remotes --grep='^git-svn-id:.*@%s'" %
+        base_svn_revision)
+    try:
+      base_revision = subprocess.check_output(get_hash_cmd, shell=True)
+      if not base_revision: raise ValueError
+    except:
+      self._Call("git fetch")
+      try:
+        base_revision = subprocess.check_output(get_hash_cmd, shell=True)
+        if not base_revision: raise ValueError
+      except:
+        self._SendResponse("Base revision not found.")
+        return False
+    code = self._Call("git checkout -f %s" % base_revision)
+    if code != 0:
+      self._SendResponse("Error trying to check out base revision.")
+      return False
+    code = self._Call("git clean -f -d")
+    if code != 0:
+      self._SendResponse("Failed to reset checkout")
+      return False
+    return True
+
+  def _ApplyPatch(self, patch):
+    if not patch: return True  # Just skip if the patch is empty.
+    patchfilename = "_dtest_incoming_patch.patch"
+    with open(patchfilename, "w") as f:
+      f.write(patch)
+    code = self._Call("git apply %s" % patchfilename)
+    if code != 0:
+      self._SendResponse("Error applying patch.")
+      return False
+    return True
+
+  def _Call(self, cmd):
+    return subprocess.call(cmd, shell=True)
+
+
+class WorkSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
+  def __init__(self, daemon):
+    address = (daemon.ip, constants.PEER_PORT)
+    SocketServer.TCPServer.__init__(self, address, WorkHandler)
+    self.job_lock = threading.Lock()
+    self.daemon = daemon