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