Skip to content

Commit

Permalink
#1211: fix html5 server on win32:
Browse files Browse the repository at this point in the history
* use untilConcludes to ensure we get data from the socket.peek () on win32
* use a thread for early connection setup code to ensure that peek() doesn't end up blocking the main thread
* add untilConcludes() wrappers for socket send and recv on win32

git-svn-id: https://xpra.org/svn/Xpra/trunk@13352 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Aug 15, 2016
1 parent 28974b9 commit de60e21
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def is_msvc():
gtk2_ENABLED = DEFAULT and client_ENABLED and not PYTHON3
gtk3_ENABLED = DEFAULT and client_ENABLED and PYTHON3
opengl_ENABLED = DEFAULT and client_ENABLED
html5_ENABLED = not WIN32 #websockify is broken on win32, see https://github.com/kanaka/websockify/issues/28
html5_ENABLED = DEFAULT
pam_ENABLED = DEFAULT and server_ENABLED and os.name=="posix" and (os.path.exists("/usr/include/pam/pam_misc.h") or os.path.exists("/usr/include/security/pam_misc.h"))

vsock_ENABLED = sys.platform.startswith("linux") and os.path.exists("/usr/include/linux/vm_sockets.h")
Expand Down
7 changes: 1 addition & 6 deletions src/xpra/net/bytestreams.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,7 @@ def __init__(self, socket, local, remote, target, info):
self.filename = remote

def peek(self, n):
try:
self._socket.settimeout(None)
return self._socket.recv(n, socket.MSG_PEEK)
except:
#this fails on win32!
pass
return self.untilConcludes(self._socket.recv, n, socket.MSG_PEEK)

def read(self, n):
return self._read(self._socket.recv, n)
Expand Down
61 changes: 48 additions & 13 deletions src/xpra/server/server_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,11 @@ def add_listen_socket(self, socktype, socket):
raise NotImplementedError()

def _new_connection(self, listener, *args):
"""
Accept the new connection,
verify that there aren't too many,
start a thread to dispatch it to the correct handler.
"""
if self._closing:
netlog.warn("ignoring new connection during shutdown")
return False
Expand Down Expand Up @@ -537,29 +542,40 @@ def _new_connection(self, listener, *args):
frominfo = ""
info_msg = "New %s connection received"

#from here on, we run in a thread, so we can poll (peek does)
def handle_new_connection():
self.handle_new_connection(conn, sock, socktype, sockname, address, target, info_msg, frominfo)
make_thread(handle_new_connection, "new-%s-connection" % socktype, True).start()
return True

def handle_new_connection(self, conn, sock, socktype, sockname, address, target, info_msg, frominfo):
"""
Use peek to decide what sort of connection this is,
and start the appropriate handler for it.
"""
def conn_err(msg="invalid packet format, not an xpra client?"):
#not an xpra client
netlog.error("Error: %s connection failed:", socktype)
netlog.error(" %s", msg)
if frominfo:
netlog.error(" %s", frominfo)
try:
sock.settimeout(1)
conn.write("disconnect: %s?\n" % msg)
conn.close()
except Exception as e:
netlog("error sending '%s': %s", nonl(msg), e)

PEEK_SIZE = 128
def peek():
PEEK_SIZE = 128
v = conn.peek(PEEK_SIZE)
netlog("peek(%i)=%s", PEEK_SIZE, binascii.hexlify(v or ""))
return v

if socktype=="tcp" and (self._html or self._tcp_proxy or self._ssl_wrap_socket):
#see if the packet data is actually xpra or something else
#that we need to handle via a tcp proxy, ssl wrapper or the websockify adapter:
sock.settimeout(10)
v = conn.peek(PEEK_SIZE)
#ugly win32 workaround (should be done in a thread or with untilConcludes?):
start = time.time()
while not v and sys.platform.startswith("win") and time.time()-start<10:
time.sleep(0.1)
v = conn.peek(128)
netlog("peek(%i)=%s", PEEK_SIZE, binascii.hexlify(v or ""))
v = peek()
if v and v[0] not in ("P", ord("P")):
if self._html:
line1 = v.splitlines()[0]
Expand All @@ -584,18 +600,23 @@ def run_websockify():
conn_err(str(e))
return True
conn = SocketConnection(sock, sockname, address, target, socktype)
v = conn.peek(PEEK_SIZE)
#peek so we can detect invalid clients early:
v = peek()
elif self._tcp_proxy:
netlog.info("New tcp proxy connection received from %s", frominfo)
def run_proxy():
self.start_tcp_proxy(conn, frominfo)
make_thread(run_proxy, "tcp-proxy-for-%s" % frominfo, daemon=True).start()
return True
else:
v = conn.peek(PEEK_SIZE)
netlog("%s.peek(%i)=%s", conn, PEEK_SIZE, binascii.hexlify(v or ""))
#peek so we can detect invalid clients early:
v = peek()
if v and v[0] not in ("P", ord("P")):
conn_err()
try:
c = ord(v[0])
except:
c = int(v[0])
conn_err("invalid packet header character '%s', not an xpra client?" % hex(c))
return True
netlog.info(info_msg)
sock.settimeout(self._socket_timeout)
Expand Down Expand Up @@ -676,6 +697,20 @@ def start_websockify(self, conn, frominfo):
from xpra.net.websocket import WebSocketConnection, WSRequestHandler
try:
sock = conn._socket
sock.setblocking(1)
if sys.platform.startswith("win"):
from xpra.net.bytestreams import untilConcludes
#workaround for win32 servers (this should not be needed on any other platform)
#which don't seem to honour our request to use blocking sockets
#maybe this should go in websockify somewhere?
saved_recv = sock.recv
saved_send = sock.send
def recv(*args):
return untilConcludes(conn.is_active, saved_recv, *args)
def send(*args):
return untilConcludes(conn.is_active, saved_send, *args)
sock.recv = recv
sock.send = send
def new_websocket_client(wsh):
netlog("new_websocket_client(%s) socket=%s", wsh, sock)
wsc = WebSocketConnection(sock, conn.local, conn.remote, conn.target, conn.info, wsh)
Expand Down

0 comments on commit de60e21

Please sign in to comment.