xmlrpcclient.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #
  2. # BitBake XMLRPC Client 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 socket
  10. import http.client
  11. import xmlrpc.client
  12. import bb
  13. from bb.ui import uievent
  14. class BBTransport(xmlrpc.client.Transport):
  15. def __init__(self, timeout):
  16. self.timeout = timeout
  17. self.connection_token = None
  18. xmlrpc.client.Transport.__init__(self)
  19. # Modified from default to pass timeout to HTTPConnection
  20. def make_connection(self, host):
  21. #return an existing connection if possible. This allows
  22. #HTTP/1.1 keep-alive.
  23. if self._connection and host == self._connection[0]:
  24. return self._connection[1]
  25. # create a HTTP connection object from a host descriptor
  26. chost, self._extra_headers, x509 = self.get_host_info(host)
  27. #store the host argument along with the connection object
  28. self._connection = host, http.client.HTTPConnection(chost, timeout=self.timeout)
  29. return self._connection[1]
  30. def set_connection_token(self, token):
  31. self.connection_token = token
  32. def send_content(self, h, body):
  33. if self.connection_token:
  34. h.putheader("Bitbake-token", self.connection_token)
  35. xmlrpc.client.Transport.send_content(self, h, body)
  36. def _create_server(host, port, timeout = 60):
  37. t = BBTransport(timeout)
  38. s = xmlrpc.client.ServerProxy("http://%s:%d/" % (host, port), transport=t, allow_none=True, use_builtin_types=True)
  39. return s, t
  40. def check_connection(remote, timeout):
  41. try:
  42. host, port = remote.split(":")
  43. port = int(port)
  44. except Exception as e:
  45. bb.warn("Failed to read remote definition (%s)" % str(e))
  46. raise e
  47. server, _transport = _create_server(host, port, timeout)
  48. try:
  49. ret, err = server.runCommand(['getVariable', 'TOPDIR'])
  50. if err or not ret:
  51. return False
  52. except ConnectionError:
  53. return False
  54. return True
  55. class BitBakeXMLRPCServerConnection(object):
  56. def __init__(self, host, port, clientinfo=("localhost", 0), observer_only = False, featureset = None):
  57. self.connection, self.transport = _create_server(host, port)
  58. self.clientinfo = clientinfo
  59. self.observer_only = observer_only
  60. if featureset:
  61. self.featureset = featureset
  62. else:
  63. self.featureset = []
  64. self.events = uievent.BBUIEventQueue(self.connection, self.clientinfo)
  65. _, error = self.connection.runCommand(["setFeatures", self.featureset])
  66. if error:
  67. # disconnect the client, we can't make the setFeature work
  68. self.connection.removeClient()
  69. # no need to log it here, the error shall be sent to the client
  70. raise BaseException(error)
  71. def connect(self, token = None):
  72. if token is None:
  73. if self.observer_only:
  74. token = "observer"
  75. else:
  76. token = self.connection.addClient()
  77. if token is None:
  78. return None
  79. self.transport.set_connection_token(token)
  80. return self
  81. def removeClient(self):
  82. if not self.observer_only:
  83. self.connection.removeClient()
  84. def terminate(self):
  85. # Don't wait for server indefinitely
  86. socket.setdefaulttimeout(2)
  87. try:
  88. self.events.system_quit()
  89. except:
  90. pass
  91. try:
  92. self.connection.removeClient()
  93. except:
  94. pass
  95. def connectXMLRPC(remote, featureset, observer_only = False, token = None):
  96. # The format of "remote" must be "server:port"
  97. try:
  98. [host, port] = remote.split(":")
  99. port = int(port)
  100. except Exception as e:
  101. bb.warn("Failed to parse remote definition %s (%s)" % (remote, str(e)))
  102. raise e
  103. # We need our IP for the server connection. We get the IP
  104. # by trying to connect with the server
  105. try:
  106. s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  107. s.connect((host, port))
  108. ip = s.getsockname()[0]
  109. s.close()
  110. except Exception as e:
  111. bb.warn("Could not create socket for %s:%s (%s)" % (host, port, str(e)))
  112. raise e
  113. try:
  114. connection = BitBakeXMLRPCServerConnection(host, port, (ip, 0), observer_only, featureset)
  115. return connection.connect(token)
  116. except Exception as e:
  117. bb.warn("Could not connect to server at %s:%s (%s)" % (host, port, str(e)))
  118. raise e