11from __future__ import annotations
22
33import os
4- import sys
54from typing import TYPE_CHECKING
65
76import trio
87import trio .socket as tsocket
98from trio import TaskStatus
109
10+ from ._highlevel_open_tcp_listeners import _compute_backlog
11+
1112if TYPE_CHECKING :
1213 from collections .abc import Awaitable , Callable
1314
2021 HAS_UNIX = False
2122
2223
23- # Default backlog size:
24- #
25- # Having the backlog too low can cause practical problems (a perfectly healthy
26- # service that starts failing to accept connections if they arrive in a
27- # burst).
28- #
29- # Having it too high doesn't really cause any problems. Like any buffer, you
30- # want backlog queue to be zero usually, and it won't save you if you're
31- # getting connection attempts faster than you can call accept() on an ongoing
32- # basis. But unlike other buffers, this one doesn't really provide any
33- # backpressure. If a connection gets stuck waiting in the backlog queue, then
34- # from the peer's point of view the connection succeeded but then their
35- # send/recv will stall until we get to it, possibly for a long time. OTOH if
36- # there isn't room in the backlog queue, then their connect stalls, possibly
37- # for a long time, which is pretty much the same thing.
38- #
39- # A large backlog can also use a bit more kernel memory, but this seems fairly
40- # negligible these days.
41- #
42- # So this suggests we should make the backlog as large as possible. This also
43- # matches what Golang does. However, they do it in a weird way, where they
44- # have a bunch of code to sniff out the configured upper limit for backlog on
45- # different operating systems. But on every system, passing in a too-large
46- # backlog just causes it to be silently truncated to the configured maximum,
47- # so this is unnecessary -- we can just pass in "infinity" and get the maximum
48- # that way. (Verified on Windows, Linux, macOS using
49- # https://github.com/python-trio/trio/wiki/notes-to-self#measure-listen-backlogpy
50- def _compute_backlog (backlog : int | None ) -> int :
51- # Many systems (Linux, BSDs, ...) store the backlog in a uint16 and are
52- # missing overflow protection, so we apply our own overflow protection.
53- # https://github.com/golang/go/issues/5030
54- if not isinstance (backlog , int ) and backlog is not None :
55- raise TypeError (f"backlog must be an int or None, not { backlog !r} " )
56- if backlog is None :
57- return 0xFFFF
58- return min (backlog , 0xFFFF )
59-
60-
6124async def open_unix_listener (
6225 path : str | bytes | os .PathLike [str ] | os .PathLike [bytes ],
6326 * ,
64- mode : int | None = None , # 0o666,
27+ mode : int | None = None ,
6528 backlog : int | None = None ,
66- ) -> trio .UnixSocketListener :
29+ ) -> trio .SocketListener :
6730 """Create :class:`SocketListener` objects to listen for connections.
6831 Opens a connection to the specified
6932 `Unix domain socket <https://en.wikipedia.org/wiki/Unix_domain_socket>`__.
@@ -76,20 +39,21 @@ async def open_unix_listener(
7639 Absolute or relative paths may be used.
7740
7841 mode (int or None): The socket file permissions.
79- UNIX permissions are usually specified in octal numbers.
80- If you leave this as ``None``, Trio will not change the mode from
42+ UNIX permissions are usually specified in octal numbers. If
43+ you leave this as ``None``, Trio will not change the mode from
8144 the operating system's default.
8245
8346 backlog (int or None): The listen backlog to use. If you leave this as
84- ``None`` then Trio will pick a good default. (Currently: whatever
85- your system has configured as the maximum backlog.)
47+ ``None`` then Trio will pick a good default. (Currently:
48+ whatever your system has configured as the maximum backlog.)
8649
8750 Returns:
8851 :class:`UnixSocketListener`
8952
9053 Raises:
91- :class:`TypeError` if invalid arguments.
54+ :class:`ValueError` If invalid arguments.
9255 :class:`RuntimeError`: If AF_UNIX sockets are not supported.
56+ :class:`FileNotFoundError`: If folder socket file is to be created in does not exist.
9357 """
9458 if not HAS_UNIX :
9559 raise RuntimeError ("Unix sockets are not supported on this platform" )
@@ -102,28 +66,23 @@ async def open_unix_listener(
10266 if not await folder .exists ():
10367 raise FileNotFoundError (f"Socket folder does not exist: { folder !r} " )
10468
105- # much more simplified logic vs tcp sockets - one socket type and only one
69+ str_path = str (fspath )
70+
71+ # much more simplified logic vs tcp sockets - one socket family and only one
10672 # possible location to connect to
10773 sock = tsocket .socket (AF_UNIX , tsocket .SOCK_STREAM )
10874 try :
109- # See https://github.com/python-trio/trio/issues/39
110- if sys .platform != "win32" :
111- sock .setsockopt (tsocket .SOL_SOCKET , tsocket .SO_REUSEADDR , 1 )
112-
113- await sock .bind (str (fspath ))
114-
115- sock .listen (computed_backlog )
75+ await sock .bind (str_path )
11676
11777 if mode is not None :
11878 await fspath .chmod (mode )
11979
120- return trio .UnixSocketListener (sock )
121- except BaseException as exc :
80+ sock .listen (computed_backlog )
81+
82+ return trio .SocketListener (sock , str_path )
83+ except BaseException :
12284 sock .close ()
123- try :
124- os .unlink (str (fspath ))
125- except BaseException as exc_2 :
126- raise exc_2 from exc
85+ os .unlink (str_path )
12786 raise
12887
12988
0 commit comments