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