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# -*- coding: utf-8 -*- 

2# This file is part of Xpra. 

3# Copyright (C) 2010-2020 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 

7from xpra.util import typedict 

8from xpra.server.source.stub_source_mixin import StubSourceMixin 

9 

10from xpra.log import Logger 

11log = Logger("mmap") 

12 

13 

14class MMAP_Connection(StubSourceMixin): 

15 

16 @classmethod 

17 def is_needed(cls, caps : typedict) -> bool: 

18 #pre 2.3 clients; 

19 if caps.strget("mmap_file"): 

20 return True 

21 v = caps.rawget("mmap") 

22 #we should be receiving a dict with mmap attributes 

23 #(but pre v4 clients also send a boolean telling us if mmap is supported by the platform..) 

24 return isinstance(v, dict) 

25 

26 def __init__(self): 

27 self.supports_mmap = False 

28 self.mmap_filename = None 

29 self.min_mmap_size = 0 

30 

31 def init_from(self, _protocol, server): 

32 self.supports_mmap = server.supports_mmap 

33 self.mmap_filename = server.mmap_filename 

34 self.min_mmap_size = server.min_mmap_size 

35 

36 def init_state(self): 

37 self.mmap = None 

38 self.mmap_size = 0 

39 self.mmap_client_token = None #the token we write that the client may check 

40 self.mmap_client_token_index = 512 

41 self.mmap_client_token_bytes = 0 

42 self.mmap_client_namespace = False 

43 

44 def cleanup(self): 

45 mmap = self.mmap 

46 if mmap: 

47 self.mmap = None 

48 self.mmap_size = 0 

49 mmap.close() 

50 

51 

52 def parse_client_caps(self, c : typedict): 

53 import os 

54 from xpra.os_util import WIN32 

55 self.mmap_client_namespace = c.boolget("mmap.namespace", False) 

56 sep = "." if self.mmap_client_namespace else "_" 

57 def mmapattr(k): 

58 return "mmap%s%s" % (sep, k) 

59 mmap_filename = c.strget(mmapattr("file")) 

60 if not mmap_filename: 

61 return 

62 mmap_size = c.intget(mmapattr("size"), 0) 

63 log("client supplied mmap_file=%s", mmap_filename) 

64 mmap_token = c.intget(mmapattr("token")) 

65 log("mmap supported=%s, token=%s", self.supports_mmap, mmap_token) 

66 if self.mmap_filename: 

67 log("using global server specified mmap file path: '%s'", self.mmap_filename) 

68 mmap_filename = self.mmap_filename 

69 if not self.supports_mmap: 

70 log("client enabled mmap but mmap mode is not supported", mmap_filename) 

71 elif WIN32 and mmap_filename.startswith("/"): 

72 log("mmap_file '%s' is a unix path", mmap_filename) 

73 elif not os.path.exists(mmap_filename): 

74 log("mmap_file '%s' cannot be found!", mmap_filename) 

75 else: 

76 from xpra.net.mmap_pipe import ( 

77 init_server_mmap, 

78 read_mmap_token, 

79 write_mmap_token, 

80 DEFAULT_TOKEN_INDEX, DEFAULT_TOKEN_BYTES, 

81 ) 

82 self.mmap, self.mmap_size = init_server_mmap(mmap_filename, mmap_size) 

83 log("found client mmap area: %s, %i bytes - min mmap size=%i", 

84 self.mmap, self.mmap_size, self.min_mmap_size) 

85 if self.mmap_size>0: 

86 index = c.intget(mmapattr("token_index"), DEFAULT_TOKEN_INDEX) 

87 count = c.intget(mmapattr("token_bytes"), DEFAULT_TOKEN_BYTES) 

88 v = read_mmap_token(self.mmap, index, count) 

89 log("mmap_token=%#x, verification=%#x", mmap_token, v) 

90 if v!=mmap_token: 

91 log.warn("Warning: mmap token verification failed, not using mmap area!") 

92 log.warn(" expected '%#x', found '%#x'", mmap_token, v) 

93 self.mmap.close() 

94 self.mmap = None 

95 self.mmap_size = 0 

96 elif self.mmap_size<self.min_mmap_size: 

97 log.warn("Warning: client supplied mmap area is too small, discarding it") 

98 log.warn(" we need at least %iMB and this area is %iMB", 

99 self.min_mmap_size//1024//1024, self.mmap_size//1024//1024) 

100 self.mmap.close() 

101 self.mmap = None 

102 self.mmap_size = 0 

103 else: 

104 from xpra.os_util import get_int_uuid 

105 self.mmap_client_token = get_int_uuid() 

106 self.mmap_client_token_bytes = DEFAULT_TOKEN_BYTES 

107 if c.intget("mmap_token_index"): 

108 #we can write the token anywhere we want and tell the client, 

109 #so write it right at the end: 

110 self.mmap_client_token_index = self.mmap_size-self.mmap_client_token_bytes 

111 else: 

112 #use the expected default for older versions: 

113 self.mmap_client_token_index = DEFAULT_TOKEN_INDEX 

114 write_mmap_token(self.mmap, 

115 self.mmap_client_token, 

116 self.mmap_client_token_index, 

117 self.mmap_client_token_bytes) 

118 if self.mmap_size>0: 

119 from xpra.simple_stats import std_unit 

120 log.info(" mmap is enabled using %sB area in %s", std_unit(self.mmap_size, unit=1024), mmap_filename) 

121 

122 def get_caps(self) -> dict: 

123 caps = {"mmap_enabled" : self.mmap_size>0} 

124 if self.mmap_client_token: 

125 sep = "." if self.mmap_client_namespace else "_" 

126 def mmapattr(name, value): 

127 caps["mmap%s%s" % (sep, name)] = value 

128 mmapattr("token", self.mmap_client_token) 

129 mmapattr("token_index", self.mmap_client_token_index) 

130 mmapattr("token_bytes", self.mmap_client_token_bytes) 

131 return caps 

132 

133 def get_info(self) -> dict: 

134 return { 

135 "mmap" : { 

136 "supported" : self.supports_mmap, 

137 "enabled" : self.mmap is not None, 

138 "size" : self.mmap_size, 

139 "filename" : self.mmap_filename or "", 

140 }, 

141 }