summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Åstrand (astrand) <astrand@cendio.se>2013-12-17 13:56:20 +0100
committerPeter Åstrand (astrand) <astrand@cendio.se>2013-12-17 13:56:20 +0100
commit8049ddfe26c64e48e3bd727ba8c989d71906cfcb (patch)
tree07395a193ff926f8b0c57c222797fa2d96608262
parent17455afe4d9d1fa386c19080d7242067de26c5fc (diff)
downloadwebsockify-8049ddfe26c64e48e3bd727ba8c989d71906cfcb.tar.gz
Cherry-picked 4e3388964af9697496d2c5e000bb8559dfba87ad from
astrand/websockify: Prepare for fixing https://github.com/kanaka/websockify/issues/71: Move around functions and methods, so that connection-related and server-related stuff are close together. This patch just moves things around - it does not change anything at all. This can be verified with: git diff websocket.py | grep ^- | cut -c 2- | sort > removed git diff websocket.py | grep ^+ | cut -c 2- | sort > added diff -u removed added
-rw-r--r--websockify/websocket.py434
1 files changed, 217 insertions, 217 deletions
diff --git a/websockify/websocket.py b/websockify/websocket.py
index add0337..d264273 100644
--- a/websockify/websocket.py
+++ b/websockify/websocket.py
@@ -74,20 +74,14 @@ class WebSocketServer(object):
log_prefix = "websocket"
buffer_size = 65536
+ GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+
server_handshake_hybi = """HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: %s\r
"""
- GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-
- policy_response = """<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>\n"""
-
- # An exception before the WebSocket connection was established
- class EClose(Exception):
- pass
-
# An exception while the WebSocket client was connected
class CClose(Exception):
pass
@@ -95,180 +89,6 @@ Sec-WebSocket-Accept: %s\r
class Terminate(Exception):
pass
- def __init__(self, listen_host='', listen_port=None, source_is_ipv6=False,
- verbose=False, cert='', key='', ssl_only=None,
- daemon=False, record='', web='',
- file_only=False, no_parent=False,
- run_once=False, timeout=0, idle_timeout=0, traffic=False,
- tcp_keepalive=True, tcp_keepcnt=None, tcp_keepidle=None,
- tcp_keepintvl=None):
-
- # settings
- self.verbose = verbose
- self.listen_host = listen_host
- self.listen_port = listen_port
- self.prefer_ipv6 = source_is_ipv6
- self.ssl_only = ssl_only
- self.daemon = daemon
- self.run_once = run_once
- self.timeout = timeout
- self.idle_timeout = idle_timeout
- self.traffic = traffic
-
- self.launch_time = time.time()
- self.ws_connection = False
- self.i_am_client = False
- self.handler_id = 1
-
- self.file_only = file_only
- self.no_parent = no_parent
-
- self.logger = self.get_logger()
- self.tcp_keepalive = tcp_keepalive
- self.tcp_keepcnt = tcp_keepcnt
- self.tcp_keepidle = tcp_keepidle
- self.tcp_keepintvl = tcp_keepintvl
-
- # Make paths settings absolute
- self.cert = os.path.abspath(cert)
- self.key = self.web = self.record = ''
- if key:
- self.key = os.path.abspath(key)
- if web:
- self.web = os.path.abspath(web)
- if record:
- self.record = os.path.abspath(record)
-
- if self.web:
- os.chdir(self.web)
-
- # Sanity checks
- if not ssl and self.ssl_only:
- raise Exception("No 'ssl' module and SSL-only specified")
- if self.daemon and not resource:
- raise Exception("Module 'resource' required to daemonize")
-
- # Show configuration
- self.msg("WebSocket server settings:")
- self.msg(" - Listen on %s:%s",
- self.listen_host, self.listen_port)
- self.msg(" - Flash security policy server")
- if self.web:
- self.msg(" - Web server. Web root: %s", self.web)
- if ssl:
- if os.path.exists(self.cert):
- self.msg(" - SSL/TLS support")
- if self.ssl_only:
- self.msg(" - Deny non-SSL/TLS connections")
- else:
- self.msg(" - No SSL/TLS support (no cert file)")
- else:
- self.msg(" - No SSL/TLS support (no 'ssl' module)")
- if self.daemon:
- self.msg(" - Backgrounding (daemon)")
- if self.record:
- self.msg(" - Recording to '%s.*'", self.record)
-
- #
- # WebSocketServer static methods
- #
-
- @staticmethod
- def get_logger():
- return logging.getLogger("%s.%s" % (
- WebSocketServer.log_prefix,
- WebSocketServer.__class__.__name__))
-
- @staticmethod
- def socket(host, port=None, connect=False, prefer_ipv6=False,
- unix_socket=None, use_ssl=False, tcp_keepalive=True,
- tcp_keepcnt=None, tcp_keepidle=None, tcp_keepintvl=None):
- """ Resolve a host (and optional port) to an IPv4 or IPv6
- address. Create a socket. Bind to it if listen is set,
- otherwise connect to it. Return the socket.
- """
- flags = 0
- if host == '':
- host = None
- if connect and not (port or unix_socket):
- raise Exception("Connect mode requires a port")
- if use_ssl and not ssl:
- raise Exception("SSL socket requested but Python SSL module not loaded.");
- if not connect and use_ssl:
- raise Exception("SSL only supported in connect mode (for now)")
- if not connect:
- flags = flags | socket.AI_PASSIVE
-
- if not unix_socket:
- addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM,
- socket.IPPROTO_TCP, flags)
- if not addrs:
- raise Exception("Could not resolve host '%s'" % host)
- addrs.sort(key=lambda x: x[0])
- if prefer_ipv6:
- addrs.reverse()
- sock = socket.socket(addrs[0][0], addrs[0][1])
-
- if tcp_keepalive:
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
- if tcp_keepcnt:
- sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT,
- tcp_keepcnt)
- if tcp_keepidle:
- sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE,
- tcp_keepidle)
- if tcp_keepintvl:
- sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL,
- tcp_keepintvl)
-
- if connect:
- sock.connect(addrs[0][4])
- if use_ssl:
- sock = ssl.wrap_socket(sock)
- else:
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.bind(addrs[0][4])
- sock.listen(100)
- else:
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- sock.connect(unix_socket)
-
- return sock
-
- @staticmethod
- def daemonize(keepfd=None, chdir='/'):
- os.umask(0)
- if chdir:
- os.chdir(chdir)
- else:
- os.chdir('/')
- os.setgid(os.getgid()) # relinquish elevations
- os.setuid(os.getuid()) # relinquish elevations
-
- # Double fork to daemonize
- if os.fork() > 0: os._exit(0) # Parent exits
- os.setsid() # Obtain new process group
- if os.fork() > 0: os._exit(0) # Parent exits
-
- # Signal handling
- signal.signal(signal.SIGTERM, signal.SIG_IGN)
- signal.signal(signal.SIGINT, signal.SIG_IGN)
-
- # Close open files
- maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
- if maxfd == resource.RLIM_INFINITY: maxfd = 256
- for fd in reversed(range(maxfd)):
- try:
- if fd != keepfd:
- os.close(fd)
- except OSError:
- _, exc, _ = sys.exc_info()
- if exc.errno != errno.EBADF: raise
-
- # Redirect I/O to /dev/null
- os.dup2(os.open(os.devnull, os.O_RDWR), sys.stdin.fileno())
- os.dup2(os.open(os.devnull, os.O_RDWR), sys.stdout.fileno())
- os.dup2(os.open(os.devnull, os.O_RDWR), sys.stderr.fileno())
@staticmethod
def unmask(buf, hlen, plen):
@@ -417,39 +237,9 @@ Sec-WebSocket-Accept: %s\r
#
- # WebSocketServer logging/output functions
- #
-
- def print_traffic(self, token="."):
- """ Show traffic flow mode. """
- if self.traffic:
- sys.stdout.write(token)
- sys.stdout.flush()
-
-
- def log(self, lvl, msg, *args, **kwargs):
- """ Wrapper around python logging """
- prefix = ""
- if self.i_am_client:
- prefix = "% 3d: " % self.handler_id
- self.logger.log(lvl, "%s%s" % (prefix, msg),
- *args, **kwargs)
-
- def msg(self, *args, **kwargs):
- """ Output message with handler_id prefix. """
- self.log(logging.INFO, *args, **kwargs)
-
- def vmsg(self, *args, **kwargs):
- """ Same as msg() but as debug. """
- self.log(logging.DEBUG, *args, **kwargs)
-
- def warn(self, *args, **kwargs):
- """ Same as msg() but as warning. """
- self.log(logging.WARN, *args, **kwargs)
-
- #
# Main WebSocketServer methods
#
+
def send_frames(self, bufs=None):
""" Encode and send WebSocket frames. Any frames already
queued will be sent first. If buf is not set then only queued
@@ -601,6 +391,190 @@ Sec-WebSocket-Accept: %s\r
return response
+ def new_websocket_client(self):
+ """ Do something with a WebSockets client connection. """
+ raise("WebSocketServer.new_websocket_client() must be overloaded")
+
+ policy_response = """<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>\n"""
+
+ # An exception before the WebSocket connection was established
+ class EClose(Exception):
+ pass
+
+ def __init__(self, listen_host='', listen_port=None, source_is_ipv6=False,
+ verbose=False, cert='', key='', ssl_only=None,
+ daemon=False, record='', web='',
+ file_only=False, no_parent=False,
+ run_once=False, timeout=0, idle_timeout=0, traffic=False,
+ tcp_keepalive=True, tcp_keepcnt=None, tcp_keepidle=None,
+ tcp_keepintvl=None):
+
+ # settings
+ self.verbose = verbose
+ self.listen_host = listen_host
+ self.listen_port = listen_port
+ self.prefer_ipv6 = source_is_ipv6
+ self.ssl_only = ssl_only
+ self.daemon = daemon
+ self.run_once = run_once
+ self.timeout = timeout
+ self.idle_timeout = idle_timeout
+ self.traffic = traffic
+
+ self.launch_time = time.time()
+ self.ws_connection = False
+ self.i_am_client = False
+ self.handler_id = 1
+
+ self.file_only = file_only
+ self.no_parent = no_parent
+
+ self.logger = self.get_logger()
+ self.tcp_keepalive = tcp_keepalive
+ self.tcp_keepcnt = tcp_keepcnt
+ self.tcp_keepidle = tcp_keepidle
+ self.tcp_keepintvl = tcp_keepintvl
+
+ # Make paths settings absolute
+ self.cert = os.path.abspath(cert)
+ self.key = self.web = self.record = ''
+ if key:
+ self.key = os.path.abspath(key)
+ if web:
+ self.web = os.path.abspath(web)
+ if record:
+ self.record = os.path.abspath(record)
+
+ if self.web:
+ os.chdir(self.web)
+
+ # Sanity checks
+ if not ssl and self.ssl_only:
+ raise Exception("No 'ssl' module and SSL-only specified")
+ if self.daemon and not resource:
+ raise Exception("Module 'resource' required to daemonize")
+
+ # Show configuration
+ self.msg("WebSocket server settings:")
+ self.msg(" - Listen on %s:%s",
+ self.listen_host, self.listen_port)
+ self.msg(" - Flash security policy server")
+ if self.web:
+ self.msg(" - Web server. Web root: %s", self.web)
+ if ssl:
+ if os.path.exists(self.cert):
+ self.msg(" - SSL/TLS support")
+ if self.ssl_only:
+ self.msg(" - Deny non-SSL/TLS connections")
+ else:
+ self.msg(" - No SSL/TLS support (no cert file)")
+ else:
+ self.msg(" - No SSL/TLS support (no 'ssl' module)")
+ if self.daemon:
+ self.msg(" - Backgrounding (daemon)")
+ if self.record:
+ self.msg(" - Recording to '%s.*'", self.record)
+
+ #
+ # WebSocketServer static methods
+ #
+
+ @staticmethod
+ def get_logger():
+ return logging.getLogger("%s.%s" % (
+ WebSocketServer.log_prefix,
+ WebSocketServer.__class__.__name__))
+
+ @staticmethod
+ def socket(host, port=None, connect=False, prefer_ipv6=False,
+ unix_socket=None, use_ssl=False, tcp_keepalive=True,
+ tcp_keepcnt=None, tcp_keepidle=None, tcp_keepintvl=None):
+ """ Resolve a host (and optional port) to an IPv4 or IPv6
+ address. Create a socket. Bind to it if listen is set,
+ otherwise connect to it. Return the socket.
+ """
+ flags = 0
+ if host == '':
+ host = None
+ if connect and not (port or unix_socket):
+ raise Exception("Connect mode requires a port")
+ if use_ssl and not ssl:
+ raise Exception("SSL socket requested but Python SSL module not loaded.");
+ if not connect and use_ssl:
+ raise Exception("SSL only supported in connect mode (for now)")
+ if not connect:
+ flags = flags | socket.AI_PASSIVE
+
+ if not unix_socket:
+ addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM,
+ socket.IPPROTO_TCP, flags)
+ if not addrs:
+ raise Exception("Could not resolve host '%s'" % host)
+ addrs.sort(key=lambda x: x[0])
+ if prefer_ipv6:
+ addrs.reverse()
+ sock = socket.socket(addrs[0][0], addrs[0][1])
+
+ if tcp_keepalive:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
+ if tcp_keepcnt:
+ sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT,
+ tcp_keepcnt)
+ if tcp_keepidle:
+ sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE,
+ tcp_keepidle)
+ if tcp_keepintvl:
+ sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL,
+ tcp_keepintvl)
+
+ if connect:
+ sock.connect(addrs[0][4])
+ if use_ssl:
+ sock = ssl.wrap_socket(sock)
+ else:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind(addrs[0][4])
+ sock.listen(100)
+ else:
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect(unix_socket)
+
+ return sock
+
+ @staticmethod
+ def daemonize(keepfd=None, chdir='/'):
+ os.umask(0)
+ if chdir:
+ os.chdir(chdir)
+ else:
+ os.chdir('/')
+ os.setgid(os.getgid()) # relinquish elevations
+ os.setuid(os.getuid()) # relinquish elevations
+
+ # Double fork to daemonize
+ if os.fork() > 0: os._exit(0) # Parent exits
+ os.setsid() # Obtain new process group
+ if os.fork() > 0: os._exit(0) # Parent exits
+
+ # Signal handling
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+ # Close open files
+ maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
+ if maxfd == resource.RLIM_INFINITY: maxfd = 256
+ for fd in reversed(range(maxfd)):
+ try:
+ if fd != keepfd:
+ os.close(fd)
+ except OSError:
+ _, exc, _ = sys.exc_info()
+ if exc.errno != errno.EBADF: raise
+
+ # Redirect I/O to /dev/null
+ os.dup2(os.open(os.devnull, os.O_RDWR), sys.stdin.fileno())
+ os.dup2(os.open(os.devnull, os.O_RDWR), sys.stdout.fileno())
+ os.dup2(os.open(os.devnull, os.O_RDWR), sys.stderr.fileno())
def do_handshake(self, sock, address):
"""
@@ -704,6 +678,36 @@ Sec-WebSocket-Accept: %s\r
# Return the WebSockets socket which may be SSL wrapped
return retsock
+ #
+ # WebSocketServer logging/output functions
+ #
+ def print_traffic(self, token="."):
+ """ Show traffic flow mode. """
+ if self.traffic:
+ sys.stdout.write(token)
+ sys.stdout.flush()
+
+
+ def log(self, lvl, msg, *args, **kwargs):
+ """ Wrapper around python logging """
+ prefix = ""
+ if self.i_am_client:
+ prefix = "% 3d: " % self.handler_id
+ self.logger.log(lvl, "%s%s" % (prefix, msg),
+ *args, **kwargs)
+
+ def msg(self, *args, **kwargs):
+ """ Output message with handler_id prefix. """
+ self.log(logging.INFO, *args, **kwargs)
+
+ def vmsg(self, *args, **kwargs):
+ """ Same as msg() but as debug. """
+ self.log(logging.DEBUG, *args, **kwargs)
+
+ def warn(self, *args, **kwargs):
+ """ Same as msg() but as warning. """
+ self.log(logging.WARN, *args, **kwargs)
+
#
# Events that can/should be overridden in sub-classes
@@ -797,10 +801,6 @@ Sec-WebSocket-Accept: %s\r
# Original socket closed by caller
self.request.close()
- def new_websocket_client(self):
- """ Do something with a WebSockets client connection. """
- raise("WebSocketServer.new_websocket_client() must be overloaded")
-
def start_server(self):
"""
Daemonize if requested. Listen for for connections. Run