Skip to content

Commit

Permalink
#417 + #540: add "auto" mode to set the bandwidth limit to 80 percent…
Browse files Browse the repository at this point in the history
… of the client's network interface speed

git-svn-id: https://xpra.org/svn/Xpra/trunk@17246 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Oct 24, 2017
1 parent 88758dc commit 5cc23ba
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 38 deletions.
2 changes: 1 addition & 1 deletion src/etc/xpra/conf.d/10_network.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ server-idle-timeout = 0
#bandwidth-limit = 1M
#10Mbps:
#bandwidth-limit = 10Mbps
bandwidth-limit = 0
bandwidth-limit = auto
3 changes: 3 additions & 0 deletions src/man/xpra.1
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,9 @@ Restrict bandwidth usage to below the limit given.
The client's value cannot raise the limit of the server.
The value may be specified using standard units, ie:
\fI1Mbps\fP or \fI500K\fP.
In \fIauto\fP mode, the client will set the bandwidth limit
value to 80% of the maximum speed of the network interface
it is using to connect to the server.
.TP

.SS Options for start, start-desktop, upgrade, proxy and shadow
Expand Down
18 changes: 16 additions & 2 deletions src/xpra/client/client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
netlog = Logger("network")
authlog = Logger("auth")

from xpra.scripts.config import InitExit
from xpra.scripts.config import InitExit, parse_with_unit
from xpra.child_reaper import getChildReaper, reaper_cleanup
from xpra.net import compression
from xpra.net.protocol import Protocol, sanity_checks
Expand All @@ -29,7 +29,7 @@
from xpra.version_util import version_compat_check, get_version_info, XPRA_VERSION
from xpra.platform.info import get_name
from xpra.os_util import get_machine_id, get_user_uuid, load_binary_file, SIGNAMES, PYTHON3, strtobytes, bytestostr, hexstr
from xpra.util import flatten_dict, typedict, updict, xor, repr_ellipsized, nonl, envbool, disconnect_is_an_error, dump_all_frames
from xpra.util import flatten_dict, typedict, updict, xor, repr_ellipsized, nonl, envbool, envint, disconnect_is_an_error, dump_all_frames
from xpra.net.file_transfer import FileTransferHandler

from xpra.exit_codes import (EXIT_OK, EXIT_CONNECTION_LOST, EXIT_TIMEOUT, EXIT_UNSUPPORTED,
Expand All @@ -52,6 +52,8 @@
SKIP_STOPPED_PRINTERS = envbool("XPRA_SKIP_STOPPED_PRINTERS", True)
PASSWORD_PROMPT = envbool("XPRA_PASSWORD_PROMPT", True)
LEGACY_SALT_DIGEST = envbool("XPRA_LEGACY_SALT_DIGEST", True)
AUTO_BANDWIDTH_PCT = envint("XPRA_AUTO_BANDWIDTH_PCT", 80)
assert AUTO_BANDWIDTH_PCT>1 and AUTO_BANDWIDTH_PCT<=100, "invalid value for XPRA_AUTO_BANDWIDTH_PCT: %i" % AUTO_BANDWIDTH_PCT


class XpraClientBase(FileTransferHandler):
Expand Down Expand Up @@ -92,6 +94,7 @@ def defaults_init(self):
self.password = None
self.password_file = None
self.password_sent = False
self.bandwidth_limit = 0
self.encryption = None
self.encryption_keyfile = None
self.server_padding_options = [DEFAULT_PADDING]
Expand Down Expand Up @@ -131,6 +134,7 @@ def init(self, opts):
self.username = opts.username
self.password = opts.password
self.password_file = opts.password_file
self.bandwidth_limit = parse_with_unit("bandwidth-limit", opts.bandwidth_limit)
self.encryption = opts.encryption or opts.tcp_encryption
if self.encryption:
crypto_backend_init()
Expand Down Expand Up @@ -387,6 +391,16 @@ def up(prefix, d):
socket_speed = pinfo.get("socket", {}).get("speed")
if socket_speed:
capabilities["connection-data"] = {"speed" : socket_speed}
bandwidth_limit = self.bandwidth_limit
log("bandwidth-limit=%s, socket-speed=%s", self.bandwidth_limit, socket_speed)
if bandwidth_limit is None:
if socket_speed:
#auto: use 80% of socket speed if we have it:
bandwidth_limit = socket_speed*AUTO_BANDWIDTH_PCT//100 or 0
else:
bandwidth_limit = 0
if bandwidth_limit>0:
capabilities["bandwidth-limit"] = bandwidth_limit

if self.encryption:
assert self.encryption in ENCRYPTION_CIPHERS
Expand Down
4 changes: 0 additions & 4 deletions src/xpra/client/ui_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ def __init__(self):
self.client_ping_latency = deque(maxlen=1000)
self._server_ok = True
self.last_ping_echoed_time = 0
self.bandwidth_limit = 0

#webcam:
self.webcam_option = ""
Expand Down Expand Up @@ -336,7 +335,6 @@ def init(self, opts):
self.title = opts.title
self.session_name = opts.session_name
self.auto_refresh_delay = opts.auto_refresh_delay
self.bandwidth_limit = opts.bandwidth_limit
if opts.max_size:
try:
self.max_window_size = [int(x.strip()) for x in opts.max_size.split("x", 1)]
Expand Down Expand Up @@ -1572,8 +1570,6 @@ def make_hello(self):
"sound.ogg-latency-fix" : True,
"av-sync" : self.av_sync,
"av-sync.delay.default" : 0, #start at 0 and rely on sound-control packets to set the correct value
#network:
"bandwidth-limit" : self.bandwidth_limit,
})
updict(capabilities, "window", {
"raise" : True,
Expand Down
35 changes: 33 additions & 2 deletions src/xpra/scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ def may_create_user_config(xpra_conf_filename=DEFAULT_XPRA_CONF_FILENAME):
"remote-clipboard" : str,
"local-clipboard" : str,
"pulseaudio-command": str,
"bandwidth-limit" : str,
"tcp-encryption" : str,
"tcp-encryption-keyfile": str,
"encryption" : str,
Expand Down Expand Up @@ -538,7 +539,6 @@ def may_create_user_config(xpra_conf_filename=DEFAULT_XPRA_CONF_FILENAME):
"gid" : int,
"min-port" : int,
"rfb-upgrade" : int,
"bandwidth-limit" : int,
#float options:
"auto-refresh-delay": float,
#boolean options:
Expand Down Expand Up @@ -826,6 +826,7 @@ def addtrailingslash(v):
"remote-clipboard" : "CLIPBOARD",
"local-clipboard" : "CLIPBOARD",
"pulseaudio-command": " ".join(DEFAULT_PULSEAUDIO_COMMAND),
"bandwidth-limit" : "auto",
"encryption" : "",
"tcp-encryption" : "",
"encryption-keyfile": "",
Expand Down Expand Up @@ -895,7 +896,6 @@ def addtrailingslash(v):
"gid" : getgid(),
"min-port" : 1024,
"rfb-upgrade" : 5,
"bandwidth-limit" : 0,
"auto-refresh-delay": 0.15,
"daemon" : CAN_DAEMONIZE,
"start-via-proxy" : None,
Expand Down Expand Up @@ -1034,6 +1034,37 @@ def print_number(i, auto_value=0):
return "auto"
return str(i)

def parse_with_unit(numtype, v, subunit="bps", min_value=250000):
#special case for bandwidth-limit, which can be specified using units:
try:
v = str(v).lower().strip()
import re
if not v or v in FALSE_OPTIONS:
return 0
elif v=="auto":
return None
else:
r = re.match('([0-9]*)(.*)', v)
assert r
i = int(r.group(1))
unit = r.group(2).lower()
if unit.endswith(subunit):
unit = unit[:-len(subunit)] #ie: 10mbps -> 10m
if unit=="b":
pass
elif unit=="k":
i *= 1000
elif unit=="m":
i *= 1000000
elif unit=="g":
i *= 1000000000
if min_value is not None:
assert i>=min_value, "value is too low"
return i
except Exception as e:
raise InitException("invalid value for %s '%s': %s" % (numtype, v, e))


def validate_config(d={}, discard=NO_FILE_OPTIONS, extras_types={}, extras_validation={}):
"""
Validates all the options given in a dict with fields as keys and
Expand Down
25 changes: 0 additions & 25 deletions src/xpra/scripts/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,31 +1133,6 @@ def ignore(defaults):
#and may have "none" or "all" special values
fixup_options(options, defaults)

#special case for bandwidth-limit, which can be specified using units:
try:
import re
v = options.bandwidth_limit
if not v:
options.bandwidth_limit = 0
else:
r = re.match('([0-9]*)(.*)', options.bandwidth_limit)
assert r
i = int(r.group(1))
unit = r.group(2).lower()
if unit.endswith("bps"):
unit = unit[:-3]
if unit=="b":
pass
elif unit=="k":
i *= 1000
elif unit=="m":
i *= 1000000
elif unit=="g":
i *= 1000000000
assert i>=250000, "value is too low"
options.bandwidth_limit = i
except Exception as e:
raise InitException("invalid bandwidth limit value '%s': %s" % (options.bandwidth_limit, e))
try:
options.dpi = int(options.dpi)
except Exception as e:
Expand Down
4 changes: 2 additions & 2 deletions src/xpra/server/server_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from xpra.version_util import XPRA_VERSION
from xpra.scripts.main import _socket_connect, full_version_str
from xpra.scripts.server import deadly_signal
from xpra.scripts.config import InitException, parse_bool, python_platform, FALSE_OPTIONS
from xpra.scripts.config import InitException, parse_bool, python_platform, parse_with_unit, FALSE_OPTIONS
from xpra.net.bytestreams import SocketConnection, SSLSocketConnection, log_new_connection, pretty_socket, SOCKET_TIMEOUT
from xpra.net.net_util import get_network_caps, get_info as get_net_info
from xpra.platform import set_name
Expand Down Expand Up @@ -209,7 +209,7 @@ def init(self, opts):
self.session_name = opts.session_name
set_name("Xpra", self.session_name or "Xpra")

self.bandwidth_limit = opts.bandwidth_limit
self.bandwidth_limit = parse_with_unit("bandwidth-limit", opts.bandwidth_limit) or 0
self.unix_socket_paths = []
self._socket_dir = opts.socket_dir or opts.socket_dirs[0]
self.encryption = opts.encryption
Expand Down
10 changes: 8 additions & 2 deletions src/xpra/server/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ def close(self):


def update_bandwidth_limits(self):
if self.bandwidth_limit<=0:
if self.bandwidth_limit<=0 or self.mmap_size>0:
return
#figure out how to distribute the bandwidth amongst the windows,
#we use the window size,
Expand Down Expand Up @@ -874,6 +874,9 @@ def conv(v):
log("windows/pixels forwarding is disabled for this client")
else:
self.parse_encoding_caps(c, min_mmap_size)
if self.mmap_size>0:
log("mmap enabled, ignoring bandwidth-limit")
self.bandwidth_limit = 0
#window filters:
try:
for object_name, property_name, operator, value in c.listget("window-filters"):
Expand Down Expand Up @@ -2309,6 +2312,9 @@ def make_window_source(self, wid, window):
if ws is None:
batch_config = self.make_batch_config(wid, window)
ww, wh = window.get_dimensions()
bandwidth_limit = self.bandwidth_limit
if self.mmap_size>0:
bandwidth_limit = 0
ws = WindowVideoSource(
self.idle_add, self.timeout_add, self.source_remove,
ww, wh,
Expand All @@ -2321,7 +2327,7 @@ def make_window_source(self, wid, window):
self.encoding, self.encodings, self.core_encodings, self.window_icon_encodings, self.encoding_options, self.icons_encoding_options,
self.rgb_formats,
self.default_encoding_options,
self.mmap, self.mmap_size, self.bandwidth_limit)
self.mmap, self.mmap_size, bandwidth_limit)
self.window_sources[wid] = ws
if len(self.window_sources)>1:
#re-distribute bandwidth:
Expand Down

0 comments on commit 5cc23ba

Please sign in to comment.