Skip to content

Commit

Permalink
Add vsock wsgi server
Browse files Browse the repository at this point in the history
  • Loading branch information
ananthb committed Apr 6, 2023
1 parent 25be347 commit 66b8600
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 3 deletions.
21 changes: 20 additions & 1 deletion src/waitress/adjustments.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import socket
import warnings

from .compat import HAS_IPV6, WIN
from .compat import CPYTHON, HAS_IPV6, LINUX, WIN
from .proxy_headers import PROXY_HEADERS

truthy = frozenset(("t", "true", "y", "yes", "on", "1"))
Expand Down Expand Up @@ -130,6 +130,7 @@ class Adjustments:
("asyncore_use_poll", asbool),
("unix_socket", str),
("unix_socket_perms", asoctal),
("vsock_socket", str),
("sockets", as_socket_list),
("channel_request_lookahead", int),
("server_name", str),
Expand Down Expand Up @@ -254,6 +255,9 @@ class Adjustments:
# Path to a Unix domain socket to use.
unix_socket_perms = 0o600

# Path to a vsock socket to use.
vsock_socket = None

# The socket options to set on receiving a connection. It is a list of
# (level, optname, value) tuples. TCP_NODELAY disables the Nagle
# algorithm for writes (Waitress already buffers its writes).
Expand Down Expand Up @@ -302,12 +306,27 @@ def __init__(self, **kw):
if "sockets" in kw and "unix_socket" in kw:
raise ValueError("unix_socket may not be set if sockets is set")

if "sockets" in kw and "vsock_socket" in kw:
raise ValueError("vsock_socket may not be set if sockets is set")

if "unix_socket" in kw and ("host" in kw or "port" in kw):
raise ValueError("unix_socket may not be set if host or port is set")

if "unix_socket" in kw and "listen" in kw:
raise ValueError("unix_socket may not be set if listen is set")

if "vsock_socket" in kw and not (LINUX and CPYTHON):
raise ValueError("vsock_socket is not supported on this platform")

if "vsock_socket" in kw and ("host" in kw or "port" in kw):
raise ValueError("vsock_socket may not be set if host or port is set")

if "vsock_socket" in kw and "listen" in kw:
raise ValueError("vsock_socket may not be set if listen is set")

if "vsock_socket" in kw and "unix_socket" in kw:
raise ValueError("vsock_socket may not be set if unix_socket is set")

if "send_bytes" in kw:
warnings.warn(
"send_bytes will be removed in a future release", DeprecationWarning
Expand Down
4 changes: 3 additions & 1 deletion src/waitress/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import sys
import warnings

# True if we are running on Windows
# Platform detection.
WIN = platform.system() == "Windows"
LINUX = platform.system() == "Linux"
CPYTHON = platform.python_implementation() == "CPython"

MAXINT = sys.maxsize
HAS_IPV6 = socket.has_ipv6
Expand Down
60 changes: 59 additions & 1 deletion src/waitress/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ def create_server(
sockinfo=sockinfo,
)

if adj.vsock_socket and hasattr(socket, "AF_VSOCK"):
sockinfo = (socket.AF_VSOCK, socket.SOCK_STREAM, None, None)
return VsockWSGIServer(
application,
map,
_start,
_sock,
dispatcher=dispatcher,
adj=adj,
sockinfo=sockinfo,
)

effective_listen = []
last_serv = None
if not adj.sockets:
Expand Down Expand Up @@ -118,6 +130,20 @@ def create_server(
effective_listen.append(
(last_serv.effective_host, last_serv.effective_port)
)
elif hasattr(socket, "AF_VSOCK") and sock.family == socket.AF_VSOCK:
last_serv = VsockWSGIServer(
application,
map,
_start,
sock,
dispatcher=dispatcher,
adj=adj,
bind_socket=False,
sockinfo=sockinfo,
)
effective_listen.append(
(last_serv.effective_host, last_serv.effective_port)
)

# We are running a single server, so we can just return the last server,
# saves us from having to create one more object
Expand Down Expand Up @@ -376,7 +402,6 @@ def set_socket_options(self, conn):


if hasattr(socket, "AF_UNIX"):

class UnixWSGIServer(BaseWSGIServer):
def __init__(
self,
Expand Down Expand Up @@ -415,6 +440,39 @@ def getsockname(self):
def fix_addr(self, addr):
return ("localhost", None)

if hasattr(socket, "AF_VSOCK"):
class VsockWSGIServer(BaseWSGIServer):
def __init__(
self,
application,
map=None,
_start=True, # test shim
_sock=None, # test shim
dispatcher=None, # dispatcher
adj=None, # adjustments
sockinfo=None, # opaque object
**kw
):
if sockinfo is None:
sockinfo = (socket.AF_VSOCK, socket.SOCK_STREAM, None, None)

super().__init__(
application,
map=map,
_start=_start,
_sock=_sock,
dispatcher=dispatcher,
adj=adj,
sockinfo=sockinfo,
**kw,
)

def bind_server_socket(self):
self.bind(self.adj.vsock_socket)

def getsockname(self):
return ("vsock", self.socket.getsockname())


# Compatibility alias.
WSGIServer = TcpWSGIServer

0 comments on commit 66b8600

Please sign in to comment.