xmlrpcclient.py 4.5 KB

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