123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- #
- # BitBake XMLRPC Server Interface
- #
- # Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
- # Copyright (C) 2006 - 2008 Richard Purdie
- #
- # SPDX-License-Identifier: GPL-2.0-only
- #
- import hashlib
- import time
- import inspect
- from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
- import bb
- # This request handler checks if the request has a "Bitbake-token" header
- # field (this comes from the client side) and compares it with its internal
- # "Bitbake-token" field (this comes from the server). If the two are not
- # equal, it is assumed that a client is trying to connect to the server
- # while another client is connected to the server. In this case, a 503 error
- # ("service unavailable") is returned to the client.
- class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
- def __init__(self, request, client_address, server):
- self.server = server
- SimpleXMLRPCRequestHandler.__init__(self, request, client_address, server)
- def do_POST(self):
- try:
- remote_token = self.headers["Bitbake-token"]
- except:
- remote_token = None
- if 0 and remote_token != self.server.connection_token and remote_token != "observer":
- self.report_503()
- else:
- if remote_token == "observer":
- self.server.readonly = True
- else:
- self.server.readonly = False
- SimpleXMLRPCRequestHandler.do_POST(self)
- def report_503(self):
- self.send_response(503)
- response = 'No more client allowed'
- self.send_header("Content-type", "text/plain")
- self.send_header("Content-length", str(len(response)))
- self.end_headers()
- self.wfile.write(bytes(response, 'utf-8'))
- class BitBakeXMLRPCServer(SimpleXMLRPCServer):
- # remove this when you're done with debugging
- # allow_reuse_address = True
- def __init__(self, interface, cooker, parent):
- # Use auto port configuration
- if (interface[1] == -1):
- interface = (interface[0], 0)
- SimpleXMLRPCServer.__init__(self, interface,
- requestHandler=BitBakeXMLRPCRequestHandler,
- logRequests=False, allow_none=True)
- self.host, self.port = self.socket.getsockname()
- self.interface = interface
- self.connection_token = None
- self.commands = BitBakeXMLRPCServerCommands(self)
- self.register_functions(self.commands, "")
- self.cooker = cooker
- self.parent = parent
- def register_functions(self, context, prefix):
- """
- Convenience method for registering all functions in the scope
- of this class that start with a common prefix
- """
- methodlist = inspect.getmembers(context, inspect.ismethod)
- for name, method in methodlist:
- if name.startswith(prefix):
- self.register_function(method, name[len(prefix):])
- def get_timeout(self, delay):
- socktimeout = self.socket.gettimeout() or delay
- return min(socktimeout, delay)
- def handle_requests(self):
- self._handle_request_noblock()
- class BitBakeXMLRPCServerCommands():
- def __init__(self, server):
- self.server = server
- self.has_client = False
- def registerEventHandler(self, host, port):
- """
- Register a remote UI Event Handler
- """
- s, t = bb.server.xmlrpcclient._create_server(host, port)
- # we don't allow connections if the cooker is running
- if (self.server.cooker.state in [bb.cooker.state.parsing, bb.cooker.state.running]):
- return None, "Cooker is busy: %s" % bb.cooker.state.get_name(self.server.cooker.state)
- self.event_handle = bb.event.register_UIHhandler(s, True)
- return self.event_handle, 'OK'
- def unregisterEventHandler(self, handlerNum):
- """
- Unregister a remote UI Event Handler
- """
- ret = bb.event.unregister_UIHhandler(handlerNum, True)
- self.event_handle = None
- return ret
- def runCommand(self, command):
- """
- Run a cooker command on the server
- """
- return self.server.cooker.command.runCommand(command, self.server.readonly)
- def getEventHandle(self):
- return self.event_handle
- def terminateServer(self):
- """
- Trigger the server to quit
- """
- self.server.parent.quit = True
- print("XMLRPC Server triggering exit")
- return
- def addClient(self):
- if self.server.parent.haveui:
- return None
- token = hashlib.md5(str(time.time()).encode("utf-8")).hexdigest()
- self.server.connection_token = token
- self.server.parent.haveui = True
- return token
- def removeClient(self):
- if self.server.parent.haveui:
- self.server.connection_token = None
- self.server.parent.haveui = False
|