xmlrpcserver.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License version 2 as
  11. # published by the Free Software Foundation.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License along
  19. # with this program; if not, write to the Free Software Foundation, Inc.,
  20. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. import os
  22. import sys
  23. import hashlib
  24. import time
  25. import inspect
  26. from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
  27. import bb
  28. # This request handler checks if the request has a "Bitbake-token" header
  29. # field (this comes from the client side) and compares it with its internal
  30. # "Bitbake-token" field (this comes from the server). If the two are not
  31. # equal, it is assumed that a client is trying to connect to the server
  32. # while another client is connected to the server. In this case, a 503 error
  33. # ("service unavailable") is returned to the client.
  34. class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
  35. def __init__(self, request, client_address, server):
  36. self.server = server
  37. SimpleXMLRPCRequestHandler.__init__(self, request, client_address, server)
  38. def do_POST(self):
  39. try:
  40. remote_token = self.headers["Bitbake-token"]
  41. except:
  42. remote_token = None
  43. if 0 and remote_token != self.server.connection_token and remote_token != "observer":
  44. self.report_503()
  45. else:
  46. if remote_token == "observer":
  47. self.server.readonly = True
  48. else:
  49. self.server.readonly = False
  50. SimpleXMLRPCRequestHandler.do_POST(self)
  51. def report_503(self):
  52. self.send_response(503)
  53. response = 'No more client allowed'
  54. self.send_header("Content-type", "text/plain")
  55. self.send_header("Content-length", str(len(response)))
  56. self.end_headers()
  57. self.wfile.write(bytes(response, 'utf-8'))
  58. class BitBakeXMLRPCServer(SimpleXMLRPCServer):
  59. # remove this when you're done with debugging
  60. # allow_reuse_address = True
  61. def __init__(self, interface, cooker, parent):
  62. # Use auto port configuration
  63. if (interface[1] == -1):
  64. interface = (interface[0], 0)
  65. SimpleXMLRPCServer.__init__(self, interface,
  66. requestHandler=BitBakeXMLRPCRequestHandler,
  67. logRequests=False, allow_none=True)
  68. self.host, self.port = self.socket.getsockname()
  69. self.interface = interface
  70. self.connection_token = None
  71. self.commands = BitBakeXMLRPCServerCommands(self)
  72. self.register_functions(self.commands, "")
  73. self.cooker = cooker
  74. self.parent = parent
  75. def register_functions(self, context, prefix):
  76. """
  77. Convenience method for registering all functions in the scope
  78. of this class that start with a common prefix
  79. """
  80. methodlist = inspect.getmembers(context, inspect.ismethod)
  81. for name, method in methodlist:
  82. if name.startswith(prefix):
  83. self.register_function(method, name[len(prefix):])
  84. def get_timeout(self, delay):
  85. socktimeout = self.socket.gettimeout() or delay
  86. return min(socktimeout, delay)
  87. def handle_requests(self):
  88. self._handle_request_noblock()
  89. class BitBakeXMLRPCServerCommands():
  90. def __init__(self, server):
  91. self.server = server
  92. self.has_client = False
  93. def registerEventHandler(self, host, port):
  94. """
  95. Register a remote UI Event Handler
  96. """
  97. s, t = bb.server.xmlrpcclient._create_server(host, port)
  98. # we don't allow connections if the cooker is running
  99. if (self.server.cooker.state in [bb.cooker.state.parsing, bb.cooker.state.running]):
  100. return None, "Cooker is busy: %s" % bb.cooker.state.get_name(self.server.cooker.state)
  101. self.event_handle = bb.event.register_UIHhandler(s, True)
  102. return self.event_handle, 'OK'
  103. def unregisterEventHandler(self, handlerNum):
  104. """
  105. Unregister a remote UI Event Handler
  106. """
  107. ret = bb.event.unregister_UIHhandler(handlerNum, True)
  108. self.event_handle = None
  109. return ret
  110. def runCommand(self, command):
  111. """
  112. Run a cooker command on the server
  113. """
  114. return self.server.cooker.command.runCommand(command, self.server.readonly)
  115. def getEventHandle(self):
  116. return self.event_handle
  117. def terminateServer(self):
  118. """
  119. Trigger the server to quit
  120. """
  121. self.server.parent.quit = True
  122. print("XMLRPC Server triggering exit")
  123. return
  124. def addClient(self):
  125. if self.server.parent.haveui:
  126. return None
  127. token = hashlib.md5(str(time.time()).encode("utf-8")).hexdigest()
  128. self.server.connection_token = token
  129. self.server.parent.haveui = True
  130. return token
  131. def removeClient(self):
  132. if self.server.parent.haveui:
  133. self.server.connection_token = None
  134. self.server.parent.haveui = False