Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/source/mmap_connection.py : 93%
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.
7from xpra.util import typedict
8from xpra.server.source.stub_source_mixin import StubSourceMixin
10from xpra.log import Logger
11log = Logger("mmap")
14class MMAP_Connection(StubSourceMixin):
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)
26 def __init__(self):
27 self.supports_mmap = False
28 self.mmap_filename = None
29 self.min_mmap_size = 0
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
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
44 def cleanup(self):
45 mmap = self.mmap
46 if mmap:
47 self.mmap = None
48 self.mmap_size = 0
49 mmap.close()
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)
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
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 }