Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/rfb/rfb_server.py : 25%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2017-2019 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
6#pylint: disable-msg=E1101
8from xpra.util import csv
9from xpra.os_util import POSIX, OSX, bytestostr
10from xpra.server.rfb.rfb_const import RFBEncoding, RFB_KEYNAMES
11from xpra.server.rfb.rfb_protocol import RFBProtocol
12from xpra.server.rfb.rfb_source import RFBSource
13from xpra.server import server_features
14from xpra.scripts.config import parse_bool, parse_number
15from xpra.log import Logger
17log = Logger("rfb")
20"""
21 Adds RFB packet handler to a server.
22"""
23class RFBServer:
25 def __init__(self):
26 self._window_to_id = {}
27 self._rfb_upgrade = 0
28 self.readonly = False
29 self.rfb_buttons = 0
30 self.x11_keycodes_for_keysym = {}
31 if POSIX and not OSX:
32 from xpra.x11.bindings.keyboard_bindings import X11KeyboardBindings #@UnresolvedImport
33 self.X11Keyboard = X11KeyboardBindings()
35 def init(self, opts):
36 if not parse_bool("rfb-upgrade", opts.rfb_upgrade):
37 self._rfb_upgrade = 0
38 else:
39 self._rfb_upgrade = parse_number(int, "rfb-upgrade", opts.rfb_upgrade, 0)
40 log("init(..) rfb-upgrade=%i", self._rfb_upgrade)
43 def _get_rfb_desktop_model(self):
44 models = tuple(self._window_to_id.keys())
45 if not models:
46 log.error("RFB: no window models to export, dropping connection")
47 return None
48 if len(models)!=1:
49 log.error("RFB can only handle a single desktop window, found %i", len(self._window_to_id))
50 return None
51 return models[0]
53 def _get_rfb_desktop_wid(self):
54 ids = tuple(self._window_to_id.values())
55 if len(ids)!=1:
56 log.error("RFB can only handle a single desktop window, found %i", len(self._window_to_id))
57 return None
58 return ids[0]
61 def handle_rfb_connection(self, conn):
62 model = self._get_rfb_desktop_model()
63 if not model:
64 conn.close()
65 return
66 def rfb_protocol_class(conn):
67 auths = self.make_authenticators("rfb", "rfb", conn)
68 assert len(auths)<=1, "rfb does not support multiple authentication modules"
69 auth = None
70 if len(auths)==1:
71 auth = auths[0]
72 return RFBProtocol(self, conn, auth,
73 self.process_rfb_packet, self.get_rfb_pixelformat, self.session_name or "Xpra Server")
74 p = self.do_make_protocol("rfb", conn, {}, rfb_protocol_class)
75 p.send_protocol_handshake()
77 def process_rfb_packet(self, proto, packet):
78 #log("RFB packet: '%s'", packet)
79 fn_name = "_process_rfb_%s" % bytestostr(packet[0]).replace("-", "_")
80 fn = getattr(self, fn_name, None)
81 if not fn:
82 log.warn("Warning: no RFB handler for %s", fn_name)
83 return
84 self.idle_add(fn, proto, packet)
87 def get_rfb_pixelformat(self):
88 model = self._get_rfb_desktop_model()
89 w, h = model.get_dimensions()
90 #w, h, bpp, depth, bigendian, truecolor, rmax, gmax, bmax, rshift, bshift, gshift
91 return w, h, 32, 32, False, True, 255, 255, 255, 16, 8, 0
93 def _process_rfb_invalid(self, proto, packet):
94 self.disconnect_protocol(proto, "invalid packet: %s" % (packet[1:]))
96 def _process_rfb_connection_lost(self, proto, packet):
97 self._process_connection_lost(proto, packet)
99 def _process_rfb_authenticated(self, proto, _packet):
100 model = self._get_rfb_desktop_model()
101 if not model:
102 proto.close()
103 return
104 self.accept_protocol(proto)
105 #use blocking sockets from now on:
106 from xpra.net.bytestreams import set_socket_timeout
107 set_socket_timeout(proto._conn, None)
108 accepted, share_count, disconnected = self.handle_sharing(proto, share=proto.share)
109 log("rfb handle sharing: accepted=%s, share count=%s, disconnected=%s", accepted, share_count, disconnected)
110 if not accepted:
111 return
112 source = RFBSource(proto, proto.share)
113 if server_features.input_devices:
114 source.keyboard_config = self.get_keyboard_config()
115 self.set_keymap(source)
116 self._server_sources[proto] = source
117 w, h = model.get_dimensions()
118 source.damage(self._window_to_id[model], model, 0, 0, w, h)
119 #ugly weak dependency,
120 #shadow servers need to be told to start the refresh timer:
121 start_refresh = getattr(self, "start_refresh", None)
122 if start_refresh:
123 for wid in tuple(self._window_to_id.values()):
124 start_refresh(wid) #pylint: disable=not-callable
126 def _process_rfb_PointerEvent(self, _proto, packet):
127 if not server_features.input_devices or self.readonly:
128 return
129 buttons, x, y = packet[1:4]
130 wid = self._get_rfb_desktop_wid()
131 self._move_pointer(wid, (x, y))
132 if buttons!=self.rfb_buttons:
133 #figure out which buttons have changed:
134 for button in range(8):
135 mask = 2**button
136 if buttons & mask != self.rfb_buttons & mask:
137 pressed = bool(buttons & mask)
138 self.button_action((x, y), 1+button, pressed, -1)
139 self.rfb_buttons = buttons
141 def _process_rfb_KeyEvent(self, proto, packet):
142 if not server_features.input_devices or self.readonly:
143 return
144 source = self.get_server_source(proto)
145 if not source:
146 return
147 pressed, p1, p2, key = packet[1:5]
148 wid = self._get_rfb_desktop_wid()
149 keyname = RFB_KEYNAMES.get(key)
150 if not keyname:
151 if 0<key<255:
152 keyname = chr(key)
153 elif self.X11Keyboard:
154 keyname = self.X11Keyboard.keysym_str(key)
155 if not keyname:
156 log.warn("rfb unknown KeyEvent: %s, %i, %i, %#x", pressed, p1, p2, key)
157 return
158 modifiers = []
159 keyval = 0
160 keycode, group = source.keyboard_config.get_keycode(0, keyname, pressed, modifiers, 0, keyname, 0)
161 log("rfb keycode(%s)=%s, %s", keyname, keycode, group)
162 if keycode:
163 is_mod = source.keyboard_config.is_modifier(keycode)
164 self._handle_key(wid, bool(pressed), keyname, keyval, keycode, modifiers, is_mod, True)
166 def _process_rfb_SetEncodings(self, _proto, packet):
167 n, encodings = packet[2:4]
168 known_encodings = [RFBEncoding.ENCODING_STR.get(x) for x in encodings if x in RFBEncoding.ENCODING_STR]
169 log("%i encodings: %s", n, csv(known_encodings))
170 unknown_encodings = [x for x in encodings if x not in RFBEncoding.ENCODING_STR]
171 if unknown_encodings:
172 log("%i unknown encodings: %s", len(unknown_encodings), csv(unknown_encodings))
174 def _process_rfb_SetPixelFormat(self, _proto, packet):
175 log("RFB: SetPixelFormat %s", packet)
176 #w, h, bpp, depth, bigendian, truecolor, rmax, gmax, bmax, rshift, bshift, gshift = packet
178 def _process_rfb_FramebufferUpdateRequest(self, _proto, packet):
179 #pressed, _, _, keycode = packet[1:5]
180 inc, x, y, w, h = packet[1:6]
181 log("RFB: FramebufferUpdateRequest inc=%s, geometry=%s", inc, (x, y, w, h))
182 if not inc:
183 model = self._get_rfb_desktop_model()
184 self.refresh_window_area(model, x, y, w, h)
186 def _process_rfb_ClientCutText(self, _proto, packet):
187 #l = packet[4]
188 text = packet[5]
189 log("got rfb clipboard text: %r", text)