OLD | NEW |
(Empty) | |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 """The discovery server used to register clients. |
| 5 |
| 6 The discovery server is started by the host controller and allows the clients |
| 7 to register themselves when they start. Authentication of the client controllers |
| 8 is based on an OTP passed to the client controller binary on startup. |
| 9 """ |
| 10 import logging |
| 11 import threading |
| 12 import xmlrpclib |
| 13 import SimpleXMLRPCServer |
| 14 |
| 15 SERVER_ADDRESS = '' |
| 16 SERVER_PORT = 31710 |
| 17 |
| 18 |
| 19 class DiscoveryServer(object): |
| 20 """Discovery server run on the host.""" |
| 21 |
| 22 def __init__(self): |
| 23 self._expected_clients = {} |
| 24 self._rpc_server = None |
| 25 self._thread = None |
| 26 |
| 27 def _RegisterClientRPC(self, otp, ip): |
| 28 """The RPC used by a client to register with the discovery server. |
| 29 |
| 30 Args: |
| 31 otp: The one time token issued by the host. |
| 32 ip: The ip address of the client. |
| 33 |
| 34 Raises: |
| 35 KeyError if the OTP isn't found in _expected_clients |
| 36 """ |
| 37 if otp not in self._expected_clients: |
| 38 raise KeyError('OTP not found') |
| 39 cb = self._expected_clients[otp] |
| 40 del self._expected_clients[otp] |
| 41 cb(ip) |
| 42 |
| 43 def RegisterClientCallback(self, otp, callback): |
| 44 """Registers a callback associated with an OTP. |
| 45 |
| 46 Args: |
| 47 otp: A one time token used by the client to authenticate. |
| 48 callback: The callback used when the client connects. |
| 49 |
| 50 Raises: |
| 51 TypeError if the callback is not callable. |
| 52 """ |
| 53 if not callable(callback): |
| 54 raise TypeError('callback is not callable') |
| 55 self._expected_clients[otp] = callback |
| 56 |
| 57 def Start(self, address=None, port=None): |
| 58 """Starts the discovery server. |
| 59 |
| 60 Args: |
| 61 address: The address to run the server on ('', 'localhost', etc). |
| 62 port: The port to run the server on. |
| 63 """ |
| 64 address = address or SERVER_ADDRESS |
| 65 port = port = SERVER_PORT |
| 66 logging.debug('Starting discovery server') |
| 67 self._rpc_server = SimpleXMLRPCServer.SimpleXMLRPCServer( |
| 68 (address, port), allow_none=True, logRequests=False) |
| 69 self._rpc_server.register_function( |
| 70 self._RegisterClientRPC, 'RegisterClient') |
| 71 self._thread = threading.Thread(target=self._rpc_server.serve_forever) |
| 72 self._thread.start() |
| 73 |
| 74 def Shutdown(self): |
| 75 """Shuts the discovery server down.""" |
| 76 if self._thread and self._thread.is_alive(): |
| 77 logging.debug('Shutting down discovery server') |
| 78 self._rpc_server.shutdown() |
| 79 |
| 80 @staticmethod |
| 81 def Connect(host): |
| 82 """Create a connection to the discovery server.""" |
| 83 server = 'http://%s:%s' % (host, SERVER_PORT) |
| 84 logging.info('Connecting to a discovery server at %s', server) |
| 85 return xmlrpclib.Server(server) |
OLD | NEW |