Hide keyboard shortcuts

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#!/usr/bin/env python 

2# This file is part of Xpra. 

3# Copyright (C) 2011-2020 Antoine Martin <antoine@xpra.org> 

4# Copyright (C) 2008, 2009, 2010 Nathaniel Smith <njs@pobox.com> 

5# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

6# later version. See the file COPYING for details. 

7 

8from collections import namedtuple 

9 

10from xpra.log import Logger 

11from xpra.net.header import FLAGS_RENCODE, FLAGS_YAML, FLAGS_BENCODE, FLAGS_NOHEADER 

12from xpra.util import envbool 

13 

14#all the encoders we know about, in best compatibility order: 

15ALL_ENCODERS = ("rencode", "bencode", "yaml", "none") 

16#order for performance: 

17PERFORMANCE_ORDER = ("rencode", "bencode", "yaml") 

18 

19Encoding = namedtuple("Encoding", ["name", "flag", "version", "encode", "decode"]) 

20 

21ENCODERS = {} 

22 

23 

24def init_rencode(): 

25 from rencode import dumps, loads, __version__ 

26 def do_rencode(v): 

27 return dumps(v), FLAGS_RENCODE 

28 return Encoding("rencode", FLAGS_RENCODE, __version__, do_rencode, loads) 

29 

30def init_bencode(): 

31 from xpra.net.bencode import bencode, bdecode, __version__ 

32 def do_bencode(v): 

33 return bencode(v), FLAGS_BENCODE 

34 def do_bdecode(data): 

35 packet, l = bdecode(data) 

36 assert len(data)==l, "expected %i bytes, but got %i" % (l, len(data)) 

37 return packet 

38 return Encoding("bencode", FLAGS_BENCODE, __version__, do_bencode, do_bdecode) 

39 

40def init_yaml(): 

41 #json messes with strings and unicode (makes it unusable for us) 

42 from yaml import dump, safe_load, __version__ 

43 def yaml_dump(v): 

44 return dump(v).encode("latin1"), FLAGS_YAML 

45 return Encoding("yaml", FLAGS_YAML, __version__, yaml_dump, safe_load) 

46 

47def init_none(): 

48 def encode(data): 

49 #just send data as a string for clients that don't understand xpra packet format: 

50 import codecs 

51 def b(x): 

52 if isinstance(x, bytes): 

53 return x 

54 return codecs.latin_1_encode(x)[0] 

55 return b(": ".join(str(x) for x in data)+"\n"), FLAGS_NOHEADER 

56 return Encoding("none", FLAGS_NOHEADER, 0, encode, None) 

57 

58 

59def init_all(): 

60 for x in list(ALL_ENCODERS)+["none"]: 

61 if not envbool("XPRA_%s" % (x.upper()), True): 

62 continue 

63 fn = globals().get("init_%s" % x) 

64 try: 

65 e = fn() 

66 assert e 

67 ENCODERS[x] = e 

68 except (ImportError, AttributeError): 

69 logger = Logger("network", "protocol") 

70 logger.debug("no %s", x, exc_info=True) 

71init_all() 

72 

73 

74def get_packet_encoding_caps() -> dict: 

75 caps = {} 

76 for name in ALL_ENCODERS: 

77 d = caps.setdefault(name, {}) 

78 e = ENCODERS.get(name) 

79 d[""] = e is not None 

80 if e is None: 

81 continue 

82 d["version"] = e.version 

83 return caps 

84 

85def get_enabled_encoders(order=ALL_ENCODERS): 

86 return tuple(x for x in order if x in ENCODERS) 

87 

88 

89def get_encoder(e): 

90 assert e in ALL_ENCODERS, "invalid encoder name: %s" % e 

91 assert e in ENCODERS, "%s is not available" % e 

92 return ENCODERS[e].encode 

93 

94def get_packet_encoding_type(protocol_flags) -> str: 

95 if protocol_flags & FLAGS_RENCODE: 

96 return "rencode" 

97 if protocol_flags & FLAGS_YAML: 

98 return "yaml" 

99 return "bencode" 

100 

101 

102def sanity_checks(): 

103 if "rencode" not in ENCODERS: 

104 log = Logger("network", "protocol") 

105 log.warn("Warning: 'rencode' packet encoder not found") 

106 log.warn(" the other packet encoders are much slower") 

107 

108 

109class InvalidPacketEncodingException(Exception): 

110 pass 

111 

112 

113def pack_one_packet(packet): 

114 from xpra.net.header import pack_header 

115 ee = get_enabled_encoders() 

116 if ee: 

117 e = get_encoder(ee[0]) 

118 data, flags = e(packet) 

119 return pack_header(flags, 0, 0, len(data))+data 

120 return str(packet) 

121 

122 

123def decode(data, protocol_flags): 

124 if isinstance(data, memoryview): 

125 data = data.tobytes() 

126 ptype = get_packet_encoding_type(protocol_flags) 

127 e = ENCODERS.get(ptype) 

128 if e: 

129 return e.decode(data) 

130 raise InvalidPacketEncodingException("%s decoder is not available" % ptype) 

131 

132 

133def main(): # pragma: no cover 

134 from xpra.util import print_nested_dict 

135 from xpra.platform import program_context 

136 with program_context("Packet Encoding", "Packet Encoding Info"): 

137 print_nested_dict(get_packet_encoding_caps()) 

138 

139 

140if __name__ == "__main__": # pragma: no cover 

141 main()