133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# Copyright 2012 the V8 project authors. All rights reserved.
233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# Redistribution and use in source and binary forms, with or without
333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# modification, are permitted provided that the following conditions are
433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# met:
533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#
633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Redistributions of source code must retain the above copyright
733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       notice, this list of conditions and the following disclaimer.
833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Redistributions in binary form must reproduce the above
933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       copyright notice, this list of conditions and the following
1033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       disclaimer in the documentation and/or other materials provided
1133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       with the distribution.
1233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Neither the name of Google Inc. nor the names of its
1333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       contributors may be used to endorse or promote products derived
1433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       from this software without specific prior written permission.
1533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#
1633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
2833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
2933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport multiprocessing
3033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport os
3133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport shutil
3233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport subprocess
3333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport threading
3433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport time
3533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
3633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom . import daemon
3733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom . import local_handler
3833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom . import presence_handler
3933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom . import signatures
4033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom . import status_handler
4133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom . import work_handler
4233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..network import perfdata
4333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
4433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
4533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgclass Server(daemon.Daemon):
4633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
4733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def __init__(self, pidfile, root, stdin="/dev/null",
4833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org               stdout="/dev/null", stderr="/dev/null"):
4933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    super(Server, self).__init__(pidfile, stdin, stdout, stderr)
5033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.root = root
5133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_handler = None
5233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_handler_thread = None
5333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.work_handler = None
5433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.work_handler_thread = None
5533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.status_handler = None
5633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.status_handler_thread = None
5733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon = None
5833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon_thread = None
5933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.peers = []
6033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.jobs = multiprocessing.cpu_count()
6133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.peer_list_lock = threading.Lock()
6233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.perf_data_lock = None
6333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon_lock = None
6433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.datadir = os.path.join(self.root, "data")
6533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    pubkey_fingerprint_filename = os.path.join(self.datadir, "mypubkey")
6633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with open(pubkey_fingerprint_filename) as f:
6733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.pubkey_fingerprint = f.read().strip()
6833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.relative_perf_filename = os.path.join(self.datadir, "myperf")
6933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if os.path.exists(self.relative_perf_filename):
7033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      with open(self.relative_perf_filename) as f:
7133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        try:
7233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          self.relative_perf = float(f.read())
7333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        except:
7433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          self.relative_perf = 1.0
7533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    else:
7633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.relative_perf = 1.0
7733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
7833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def run(self):
7933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    os.nice(20)
8033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.ip = presence_handler.GetOwnIP()
8133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.perf_data_manager = perfdata.PerfDataManager(self.datadir)
8233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.perf_data_lock = threading.Lock()
8333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
8433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_handler = local_handler.LocalSocketServer(self)
8533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_handler_thread = threading.Thread(
8633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        target=self.local_handler.serve_forever)
8733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_handler_thread.start()
8833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
8933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.work_handler = work_handler.WorkSocketServer(self)
9033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.work_handler_thread = threading.Thread(
9133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        target=self.work_handler.serve_forever)
9233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.work_handler_thread.start()
9333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
9433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.status_handler = status_handler.StatusSocketServer(self)
9533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.status_handler_thread = threading.Thread(
9633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        target=self.status_handler.serve_forever)
9733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.status_handler_thread.start()
9833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
9933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon = presence_handler.PresenceDaemon(self)
10033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon_thread = threading.Thread(
10133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        target=self.presence_daemon.serve_forever)
10233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon_thread.start()
10333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
10433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon.FindPeers()
10533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    time.sleep(0.5)  # Give those peers some time to reply.
10633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
10733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.peer_list_lock:
10833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for p in self.peers:
10933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if p.address == self.ip: continue
11033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        status_handler.RequestTrustedPubkeys(p, self)
11133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
11233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    while True:
11333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      try:
11433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        self.PeriodicTasks()
11533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        time.sleep(60)
11633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      except Exception, e:
11733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        print("MAIN LOOP EXCEPTION: %s" % e)
11833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        self.Shutdown()
11933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        break
12033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      except KeyboardInterrupt:
12133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        self.Shutdown()
12233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        break
12333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
12433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def Shutdown(self):
12533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with open(self.relative_perf_filename, "w") as f:
12633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      f.write("%s" % self.relative_perf)
12733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon.shutdown()
12833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.presence_daemon.server_close()
12933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_handler.shutdown()
13033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_handler.server_close()
13133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.work_handler.shutdown()
13233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.work_handler.server_close()
13333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.status_handler.shutdown()
13433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.status_handler.server_close()
13533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
13633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def PeriodicTasks(self):
13733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    # If we know peers we don't trust, see if someone else trusts them.
13833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.peer_list_lock:
13933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for p in self.peers:
14033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if p.trusted: continue
14133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if self.IsTrusted(p.pubkey):
14233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          p.trusted = True
14333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          status_handler.ITrustYouNow(p)
14433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          continue
14533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        for p2 in self.peers:
14633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          if not p2.trusted: continue
14733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          status_handler.TryTransitiveTrust(p2, p.pubkey, self)
14833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    # TODO: Ping for more peers waiting to be discovered.
14933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    # TODO: Update the checkout (if currently idle).
15033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
15133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def AddPeer(self, peer):
15233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.peer_list_lock:
15333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for p in self.peers:
15433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if p.address == peer.address:
15533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          return
15633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.peers.append(peer)
15733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if peer.trusted:
15833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      status_handler.ITrustYouNow(peer)
15933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
16033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def DeletePeer(self, peer_address):
16133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.peer_list_lock:
16233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for i in xrange(len(self.peers)):
16333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if self.peers[i].address == peer_address:
16433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          del self.peers[i]
16533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          return
16633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
16733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def MarkPeerAsTrusting(self, peer_address):
16833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.peer_list_lock:
16933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for p in self.peers:
17033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if p.address == peer_address:
17133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          p.trusting_me = True
17233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          break
17333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
17433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def UpdatePeerPerformance(self, peer_address, performance):
17533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.peer_list_lock:
17633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for p in self.peers:
17733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if p.address == peer_address:
17833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          p.relative_performance = performance
17933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
18033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def CopyToTrusted(self, pubkey_filename):
18133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with open(pubkey_filename, "r") as f:
18233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      lines = f.readlines()
18333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      fingerprint = lines[-1].strip()
18433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    target_filename = self._PubkeyFilename(fingerprint)
18533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    shutil.copy(pubkey_filename, target_filename)
18633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.peer_list_lock:
18733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for peer in self.peers:
18833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if peer.address == self.ip: continue
18933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if peer.pubkey == fingerprint:
19033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          status_handler.ITrustYouNow(peer)
19133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        else:
19233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          result = self.SignTrusted(fingerprint)
19333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          status_handler.NotifyNewTrusted(peer, result)
19433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    return fingerprint
19533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
19633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def _PubkeyFilename(self, pubkey_fingerprint):
19733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    return os.path.join(self.root, "trusted", "%s.pem" % pubkey_fingerprint)
19833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
19933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def IsTrusted(self, pubkey_fingerprint):
20033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    return os.path.exists(self._PubkeyFilename(pubkey_fingerprint))
20133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
20233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def ListTrusted(self):
20333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    path = os.path.join(self.root, "trusted")
20433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if not os.path.exists(path): return []
20533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    return [ f[:-4] for f in os.listdir(path) if f.endswith(".pem") ]
20633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
20733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def SignTrusted(self, pubkey_fingerprint):
20833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if not self.IsTrusted(pubkey_fingerprint):
20933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      return []
21033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    filename = self._PubkeyFilename(pubkey_fingerprint)
21133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    result = signatures.ReadFileAndSignature(filename)  # Format: [key, sig].
21233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    return [pubkey_fingerprint, result[0], result[1], self.pubkey_fingerprint]
21333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
21433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def AcceptNewTrusted(self, data):
21533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    # The format of |data| matches the return value of |SignTrusted()|.
21633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if not data: return
21733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    fingerprint = data[0]
21833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    pubkey = data[1]
21933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    signature = data[2]
22033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    signer = data[3]
22133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if not self.IsTrusted(signer):
22233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      return
22333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if self.IsTrusted(fingerprint):
22433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      return  # Already trust this guy.
22533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    filename = self._PubkeyFilename(fingerprint)
22633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    signer_pubkeyfile = self._PubkeyFilename(signer)
22733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if not signatures.VerifySignature(filename, pubkey, signature,
22833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                                      signer_pubkeyfile):
22933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      return
23033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    return  # Nothing more to do.
23133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
23233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def AddPerfData(self, test_key, duration, arch, mode):
23333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    data_store = self.perf_data_manager.GetStore(arch, mode)
23433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    data_store.RawUpdatePerfData(str(test_key), duration)
23533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
23633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def CompareOwnPerf(self, test, arch, mode):
23733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    data_store = self.perf_data_manager.GetStore(arch, mode)
23833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    observed = data_store.FetchPerfData(test)
23933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if not observed: return
24033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    own_perf_estimate = observed / test.duration
24133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.perf_data_lock:
24233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      kLearnRateLimiter = 9999
24333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.relative_perf *= kLearnRateLimiter
24433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.relative_perf += own_perf_estimate
24533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.relative_perf /= (kLearnRateLimiter + 1)
246