xmlrpcserver.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #
  2. # BitBake XMLRPC Server Interface
  3. #
  4. # Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
  5. # Copyright (C) 2006 - 2008 Richard Purdie
  6. #
  7. # SPDX-License-Identifier: GPL-2.0-only
  8. #
  9. import hashlib
  10. import time
  11. import inspect
  12. from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
  13. import bb
  14. # This request handler checks if the request has a "Bitbake-token" header
  15. # field (this comes from the client side) and compares it with its internal
  16. # "Bitbake-token" field (this comes from the server). If the two are not
  17. # equal, it is assumed that a client is trying to connect to the server
  18. # while another client is connected to the server. In this case, a 503 error
  19. # ("service unavailable") is returned to the client.
  20. class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
  21. def __init__(self, request, client_address, server):
  22. self.server = server
  23. SimpleXMLRPCRequestHandler.__init__(self, request, client_address, server)
  24. def do_POST(self):
  25. try:
  26. remote_token = self.headers["Bitbake-token"]
  27. except:
  28. remote_token = None
  29. if 0 and remote_token != self.server.connection_token and remote_token != "observer":
  30. self.report_503()
  31. else:
  32. if remote_token == "observer":
  33. self.server.readonly = True
  34. else:
  35. self.server.readonly = False
  36. SimpleXMLRPCRequestHandler.do_POST(self)
  37. def report_503(self):
  38. self.send_response(503)
  39. response = 'No more client allowed'
  40. self.send_header("Content-type", "text/plain")
  41. self.send_header("Content-length", str(len(response)))
  42. self.end_headers()
  43. self.wfile.write(bytes(response, 'utf-8'))
  44. class BitBakeXMLRPCServer(SimpleXMLRPCServer):
  45. # remove this when you're done with debugging
  46. # allow_reuse_address = True
  47. def __init__(self, interface, cooker, parent):
  48. # Use auto port configuration
  49. if (interface[1] == -1):
  50. interface = (interface[0], 0)
  51. SimpleXMLRPCServer.__init__(self, interface,
  52. requestHandler=BitBakeXMLRPCRequestHandler,
  53. logRequests=False, allow_none=True)
  54. self.host, self.port = self.socket.getsockname()
  55. self.interface = interface
  56. self.connection_token = None
  57. self.commands = BitBakeXMLRPCServerCommands(self)
  58. self.register_functions(self.commands, "")
  59. self.cooker = cooker
  60. self.parent = parent
  61. def register_functions(self, context, prefix):
  62. """
  63. Convenience method for registering all functions in the scope
  64. of this class that start with a common prefix
  65. """
  66. methodlist = inspect.getmembers(context, inspect.ismethod)
  67. for name, method in methodlist:
  68. if name.startswith(prefix):
  69. self.register_function(method, name[len(prefix):])
  70. def get_timeout(self, delay):
  71. socktimeout = self.socket.gettimeout() or delay
  72. return min(socktimeout, delay)
  73. def handle_requests(self):
  74. self._handle_request_noblock()
  75. class BitBakeXMLRPCServerCommands():
  76. def __init__(self, server):
  77. self.server = server
  78. self.has_client = False
  79. def registerEventHandler(self, host, port):
  80. """
  81. Register a remote UI Event Handler
  82. """
  83. s, t = bb.server.xmlrpcclient._create_server(host, port)
  84. # we don't allow connections if the cooker is running
  85. if (self.server.cooker.state in [bb.cooker.state.parsing, bb.cooker.state.running]):
  86. return None, "Cooker is busy: %s" % bb.cooker.state.get_name(self.server.cooker.state)
  87. self.event_handle = bb.event.register_UIHhandler(s, True)
  88. return self.event_handle, 'OK'
  89. def unregisterEventHandler(self, handlerNum):
  90. """
  91. Unregister a remote UI Event Handler
  92. """
  93. ret = bb.event.unregister_UIHhandler(handlerNum, True)
  94. self.event_handle = None
  95. return ret
  96. def runCommand(self, command):
  97. """
  98. Run a cooker command on the server
  99. """
  100. return self.server.cooker.command.runCommand(command, self.server.readonly)
  101. def getEventHandle(self):
  102. return self.event_handle
  103. def terminateServer(self):
  104. """
  105. Trigger the server to quit
  106. """
  107. self.server.parent.quit = True
  108. print("XMLRPC Server triggering exit")
  109. return
  110. def addClient(self):
  111. if self.server.parent.haveui:
  112. return None
  113. token = hashlib.md5(str(time.time()).encode("utf-8")).hexdigest()
  114. self.server.connection_token = token
  115. self.server.parent.haveui = True
  116. return token
  117. def removeClient(self):
  118. if self.server.parent.haveui:
  119. self.server.connection_token = None
  120. self.server.parent.haveui = False