def bind_unix_socket(file, mode=0o600, backlog=128):
        """Creates a listening unix socket.

        If a socket with the given name already exists, it will be deleted.
        If any other file with that name exists, an exception will be
        raised.

        Returns a socket object (not a list of socket objects like
        `bind_sockets`)
        """
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        set_close_exec(sock.fileno())
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.setblocking(0)
        try:
            st = os.stat(file)
        except OSError as err:
            if err.errno != errno.ENOENT:
                raise
        else:
            if stat.S_ISSOCK(st.st_mode):
                os.remove(file)
            else:
                raise ValueError("File %s exists and is not a socket", file)
        sock.bind(file)
        os.chmod(file, mode)
        sock.listen(backlog)
        return sock
Exemple #2
0
    def __init__(self, listener, application=None, backlog=2048,
                 socket_type=socket.SOCK_STREAM,
                 address_family=socket.AF_INET):
        self.address_family = address_family
        self.socket_type = socket_type
        host, port = listener

        if isinstance(application, Application):
            self._server = HTTPServer(application)
        elif isinstance(application, TCPServer):
            self._server = application
        elif callable(application):
            tapp = tornado.wsgi.WSGIContainer(application)
            self._server = HTTPServer(tapp)
        else:
            raise TypeError(
                "Unsupported application type: %r" % (application,))

        if host.startswith('fd://'):
            fd = int(host.split('://')[1])
            set_close_exec(fd)
            sock = socket.fromfd(fd, address_family, socket_type)
            sock.setblocking(0)
            socks = [sock]
        elif self.address_family == socket.AF_UNIX:
            filename = host[len('unix:'):]
            sock = tornado.netutil.bind_unix_socket(filename, backlog=backlog)
            socks = [sock]
        else:
            socks = tornado.netutil.bind_sockets(
                port, host, address_family, backlog)
        self._server.add_sockets(socks)
        self.application = application
Exemple #3
0
def GetSecretFile(secret):
  """Fetches the named secret into a temporary file for use with
  modules requiring the contents be accessible via a named file (e.g.
  Python SSL for keys and certificates).
  """
  if sys.platform.startswith('linux'):
    # Linux-specific implementation:  use an unnamed tempfile, which
    # will cease to exist when this process does.  Use /dev/fd to get
    # a name for the file.
    # Note that other platforms (including Mac) have /dev/fd as well,
    # but its semantics are different (all copies of a /dev/fd
    # file share one seek position, and that position is not reset on
    # open), so it's only safe to use on linux.
    if secret not in _tempfile_map:
      f = tempfile.TemporaryFile()
      set_close_exec(f.fileno())
      f.write(GetSecret(secret))
      f.flush()
      _tempfile_map[secret] = f

    return '/dev/fd/%d' % _tempfile_map[secret].fileno()
  else:
    # Default implementation: use a normal named tempfile, and delete
    # it when possible with atexit.
    if secret not in _tempfile_map:
      _, name = tempfile.mkstemp()
      with open(name, 'w') as f:
        f.write(GetSecret(secret))
      _tempfile_map[secret] = name
      atexit.register(os.remove, name)

    return _tempfile_map[secret]
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.
    """
    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                      0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if e.args[0] == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #5
0
    def bind_unix_socket(
        file: str, mode: int = 0o600, backlog: int = _DEFAULT_BACKLOG
    ) -> socket.socket:
        """Creates a listening unix socket.

        If a socket with the given name already exists, it will be deleted.
        If any other file with that name exists, an exception will be
        raised.

        Returns a socket object (not a list of socket objects like
        `bind_sockets`)
        """
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        set_close_exec(sock.fileno())
        try:
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        except socket.error as e:
            if errno_from_exception(e) != errno.ENOPROTOOPT:
                # Hurd doesn't support SO_REUSEADDR
                raise
        sock.setblocking(False)
        try:
            st = os.stat(file)
        except OSError as err:
            if errno_from_exception(err) != errno.ENOENT:
                raise
        else:
            if stat.S_ISSOCK(st.st_mode):
                os.remove(file)
            else:
                raise ValueError("File %s exists and is not a socket", file)
        sock.bind(file)
        os.chmod(file, mode)
        sock.listen(backlog)
        return sock
Exemple #6
0
 def accept_handler(fd: socket.socket, events: int) -> None:
     # More connections may come in while we're handling callbacks;
     # to prevent starvation of other tasks we must limit the number
     # of connections we accept at a time.  Ideally we would accept
     # up to the number of connections that were waiting when we
     # entered this method, but this information is not available
     # (and rearranging this method to call accept() as many times
     # as possible before running any callbacks would have adverse
     # effects on load balancing in multiprocess configurations).
     # Instead, we use the (default) listen backlog as a rough
     # heuristic for the number of connections we can reasonably
     # accept at once.
     for i in range(_DEFAULT_BACKLOG):
         if removed[0]:
             # The socket was probably closed
             return
         try:
             connection, address = sock.accept()
         except socket.error as e:
             # _ERRNO_WOULDBLOCK indicate we have accepted every
             # connection that is available.
             if errno_from_exception(e) in _ERRNO_WOULDBLOCK:
                 return
             # ECONNABORTED indicates that there was a connection
             # but it was closed while still in the accept queue.
             # (observed on FreeBSD).
             if errno_from_exception(e) == errno.ECONNABORTED:
                 continue
             raise
         set_close_exec(connection.fileno())
         callback(connection, address)
Exemple #7
0
 def _create_stream(self, max_buffer_size, af, addr, source_ip=None,
                    source_port=None):
     # Always connect in plaintext; we'll convert to ssl if necessary
     # after one connection has completed.
     source_port_bind = source_port if isinstance(source_port, int) else 0
     source_ip_bind = source_ip
     if source_port_bind and not source_ip:
         # User required a specific port, but did not specify
         # a certain source IP, will bind to the default loopback.
         source_ip_bind = '::1' if af == socket.AF_INET6 else '127.0.0.1'
         # Trying to use the same address family as the requested af socket:
         # - 127.0.0.1 for IPv4
         # - ::1 for IPv6
     socket_obj = socket.socket(af)
     set_close_exec(socket_obj.fileno())
     if source_port_bind or source_ip_bind:
         # If the user requires binding also to a specific IP/port.
         try:
             socket_obj.bind((source_ip_bind, source_port_bind))
         except socket.error:
             socket_obj.close()
             # Fail loudly if unable to use the IP/port.
             raise
     try:
         stream = IOStream(socket_obj,
                           max_buffer_size=max_buffer_size)
     except socket.error as e:
         fu = Future()
         fu.set_exception(e)
         return fu
     else:
         return stream, stream.connect(addr)
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128):
    """ 创建绑定到指定端口和地址的监听sockets,返回socket对象的一个list。 """
    sockets = []
    if address == "":
        address = None
    flags = socket.AI_PASSIVE  # server socket
    if hasattr(socket, "AI_ADDRCONFIG"):
        # AI_ADDRCONFIG ensures that we only try to bind on ipv6 if the system is configured for it,
        # but the flag doesn't exist on some platforms (specifically WinXP, although newer versions of windows have it)
        flags |= socket.AI_ADDRCONFIG
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        if os.name != "nt":
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default, but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems, separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)  # 开始监听,非阻塞
        sockets.append(sock)
    return sockets
Exemple #9
0
    def initialize(self, impl, time_func=None):
        super(PollIOLoop, self).initialize()
        self._impl = impl
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())
        self.time_func = time_func or time.time
        self._handlers = {}
        self._events = {}
        self._callbacks = []
        self._callback_lock = threading.Lock()
        self._timeouts = []
        self._cancellations = 0
        self._running = False
        self._stopped = False
        self._closing = False
        self._thread_ident = None
        self._blocking_signal_threshold = None
        self._timeout_counter = itertools.count()

        # Create a pipe that we send bogus data to when we want to wake
        # the I/O loop when it is idle
        self._waker = Waker()
        self.add_handler(self._waker.fileno(),
                         lambda fd, events: self._waker.consume(),
                         self.READ)
    def socket(self, family=socket.AF_UNSPEC):
        """Return a Unix domain socket instead of tcp socket"""

        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        set_close_exec(sock.fileno())
        sock.setblocking(0)
        
        return sock
Exemple #11
0
 def setUp(self):
     self._reactor = TornadoReactor(IOLoop())
     r, w = os.pipe()
     self._set_nonblocking(r)
     self._set_nonblocking(w)
     set_close_exec(r)
     set_close_exec(w)
     self._p1 = os.fdopen(r, "rb", 0)
     self._p2 = os.fdopen(w, "wb", 0)
Exemple #12
0
 def setUp(self):
     super(ReactorReaderWriterTest, self).setUp()
     r, w = os.pipe()
     self._set_nonblocking(r)
     self._set_nonblocking(w)
     set_close_exec(r)
     set_close_exec(w)
     self._p1 = os.fdopen(r, "rb", 0)
     self._p2 = os.fdopen(w, "wb", 0)
Exemple #13
0
 def setUp(self):
     self._reactor = TornadoReactor(IOLoop())
     r, w = os.pipe()
     self._set_nonblocking(r)
     self._set_nonblocking(w)
     set_close_exec(r)
     set_close_exec(w)
     self._p1 = os.fdopen(r, "rb", 0)
     self._p2 = os.fdopen(w, "wb", 0)
Exemple #14
0
 def setUp(self):
     super(ReactorReaderWriterTest, self).setUp()
     r, w = os.pipe()
     self._set_nonblocking(r)
     self._set_nonblocking(w)
     set_close_exec(r)
     set_close_exec(w)
     self._p1 = os.fdopen(r, "rb", 0)
     self._p2 = os.fdopen(w, "wb", 0)
Exemple #15
0
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either socket.AF_INET
    or socket.AF_INET6 to restrict to ipv4 or ipv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    ``socket.listen()``.
    """
    sockets = []
    if address == "":
        address = None
    flags = socket.AI_PASSIVE
    if hasattr(socket, "AI_ADDRCONFIG"):
        # AI_ADDRCONFIG ensures that we only try to bind on ipv6
        # if the system is configured for it, but the flag doesn't
        # exist on some platforms (specifically WinXP, although
        # newer versions of windows have it)
        flags |= socket.AI_ADDRCONFIG
    for res in set(
            socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0,
                               flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())

        ## The semantics of SO_REUSEADDR is very different from what is
        ## actually specified and implemented on various Unix flavours.
        if platform.system() != 'Windows':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #16
0
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.
    """
    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                      0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #17
0
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either socket.AF_INET
    or socket.AF_INET6 to restrict to ipv4 or ipv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    ``socket.listen()``.
    """
    sockets = []
    if address == "":
        address = None
    flags = socket.AI_PASSIVE
    if hasattr(socket, "AI_ADDRCONFIG"):
        # AI_ADDRCONFIG ensures that we only try to bind on ipv6
        # if the system is configured for it, but the flag doesn't
        # exist on some platforms (specifically WinXP, although
        # newer versions of windows have it)
        flags |= socket.AI_ADDRCONFIG
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                  0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())

        ## The semantics of SO_REUSEADDR is very different from what is
        ## actually specified and implemented on various Unix flavours.
        if platform.system() != 'Windows':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #18
0
    def socket(self, family=socket.AF_UNSPEC):
        res = socket.getaddrinfo(self._host, self._port, family,
                                 socket.SOCK_STREAM, 0, socket.AI_PASSIVE)[0]
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        sock.setblocking(0)
        if af == socket.AF_INET6:
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        return sock
    def test_set_close_exec(self):
        # set_close_exec works with sockets.
        s = socket.socket()
        self.addCleanup(s.close)
        set_close_exec(s.fileno())

        # But it doesn't work with pipes.
        r, w = os.pipe()
        self.addCleanup(functools.partial(os.close, r))
        self.addCleanup(functools.partial(os.close, w))
        with self.assertRaises(WindowsError):
            set_close_exec(r)
Exemple #20
0
    def socket(self, family=socket.AF_UNSPEC):
        res = socket.getaddrinfo(self._host, self._port, family,
                                 socket.SOCK_STREAM, 0, socket.AI_PASSIVE)[0]
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        sock.setblocking(0)
        if af == socket.AF_INET6:
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        return sock
Exemple #21
0
    def test_set_close_exec(self):
        # set_close_exec works with sockets.
        s = socket.socket()
        self.addCleanup(s.close)
        set_close_exec(s.fileno())

        # But it doesn't work with pipes.
        r, w = os.pipe()
        self.addCleanup(functools.partial(os.close, r))
        self.addCleanup(functools.partial(os.close, w))
        with self.assertRaises(WindowsError):
            set_close_exec(r)
Exemple #22
0
    def test_set_close_exec(self):
        # set_close_exec works with sockets.
        s = socket.socket()
        self.addCleanup(s.close)
        set_close_exec(s.fileno())

        # But it doesn't work with pipes.
        r, w = os.pipe()
        self.addCleanup(functools.partial(os.close, r))
        self.addCleanup(functools.partial(os.close, w))
        with self.assertRaises(WindowsError) as cm:
            set_close_exec(r)
        ERROR_INVALID_HANDLE = 6
        self.assertEqual(cm.exception.winerror, ERROR_INVALID_HANDLE)
Exemple #23
0
    def test_set_close_exec(self):
        # set_close_exec works with sockets.
        s = socket.socket()
        self.addCleanup(s.close)
        set_close_exec(s.fileno())

        # But it doesn't work with pipes.
        r, w = os.pipe()
        self.addCleanup(functools.partial(os.close, r))
        self.addCleanup(functools.partial(os.close, w))
        with self.assertRaises(WindowsError) as cm:
            set_close_exec(r)
        ERROR_INVALID_HANDLE = 6
        self.assertEqual(cm.exception.winerror, ERROR_INVALID_HANDLE)
    def __init__(self, portal, name):
        self.portal = portal
        self.name = name
        self.port = portal.AcquirePort()
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.setblocking(0)
        self.sock.bind((server.config.hostname, self.port))
        set_close_exec(self.sock.fileno())

        self.Log('starting socket server. fd %d' % self.sock.fileno())
        def OnSocketReady(fd, events):
            self.OnSocketReady(fd, events)

        server.ioloop.add_handler(self.sock.fileno(), OnSocketReady, server.ioloop.READ)
Exemple #25
0
    def _start_background_udev_monitoring(self):
        monitor = pyudev.Monitor.from_netlink(self.context, 'udev')
        monitor.filter_by(subsystem='net')
        monitor.start()

        monitor_fileno = monitor.fileno()

        # we do not trust the udev library....
        set_close_exec(monitor_fileno)
        fcntl.fcntl(monitor_fileno, fcntl.F_SETFL, fcntl.fcntl(monitor_fileno, fcntl.F_GETFL, 0) | os.O_NONBLOCK)

        io_loop = IOLoop.instance()

        fd_handler = partial(self._handle_udev_event, partial(monitor.poll, 0))
        io_loop.add_handler(monitor_fileno, fd_handler, IOLoop.READ | IOLoop.ERROR)
Exemple #26
0
    def _create_stream(self,
                       max_buffer_size,
                       af,
                       addr,
                       source_ip=None,
                       source_port=None):
        # Always connect in plaintext; we'll convert to ssl if necessary
        # after one connection has completed.
        source_port_bind = source_port if isinstance(source_port, int) else 0
        source_ip_bind = source_ip

        socket_obj = socket.socket(af)
        set_close_exec(socket_obj.fileno())
        try:
            stream = IOStream(socket_obj,
                              io_loop=self.io_loop,
                              max_buffer_size=max_buffer_size)

            # connect proxy
            if source_port_bind or source_ip_bind:

                @gen.coroutine
                def _(addr):
                    proxy_headers = get_proxy_headers(source_ip_bind)
                    parsed = urlparse(source_ip_bind)
                    scheme, host, port = parsed.scheme, parsed.hostname, source_port_bind
                    if 'socks' in scheme:
                        r = yield self._negotiate_socks(
                            addr, (source_ip_bind, source_port_bind))
                        raise gen.Return(r)
                    elif scheme in ('http', 'https'):
                        r = yield stream.connect((host, port))
                        if scheme == 'https':
                            yield self._connect_tunnel(stream, addr,
                                                       proxy_headers)
                        raise gen.Return(r)
                    else:
                        raise AttributeError('Unknown scheme: %s' % scheme)

                return _(addr)
            else:
                return stream.connect(addr)
        except socket.error as e:
            fu = Future()
            fu.set_exception(e)
            return fu
Exemple #27
0
    def __init__(self, impl=None):
        self._impl = impl or _poll()
        if hasattr(self._impl, "fileno"):
            set_close_exec(self._impl.fileno())
        self._handlers = {}
        self._events = {}
        self._callbacks = []
        self._timeouts = []
        self._running = False
        self._stopped = False
        self._thread_ident = None
        self._blocking_signal_threshold = None

        # Create a pipe that we send bogus data to when we want to wake
        # the I/O loop when it is idle
        self._waker = Waker()
        self.add_handler(self._waker.fileno(), lambda fd, events: self._waker.consume(), self.READ)
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either socket.AF_INET
    or socket.AF_INET6 to restrict to ipv4 or ipv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    ``socket.listen()``.
    """
    sockets = []
    if address == "":
        address = None
    flags = socket.AI_PASSIVE
    for res in set(
            socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0,
                               flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #29
0
    def __init__(self, impl=None):
        self._impl = impl or _poll()
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())
        self._handlers = {}
        self._events = {}
        self._callbacks = []
        self._timeouts = []
        self._running = False
        self._stopped = False
        self._thread_ident = None
        self._blocking_signal_threshold = None

        # Create a pipe that we send bogus data to when we want to wake
        # the I/O loop when it is idle
        self._waker = Waker()
        self.add_handler(self._waker.fileno(),
                         lambda fd, events: self._waker.consume(), self.READ)
Exemple #30
0
    def initialize(self, impl, time_func=None):
        super(PollIOLoop, self).initialize()

        # 使用的模型,使用的哪一个 select epoll kqueue
        # ubuntu系统使用的epoll
        self._impl = impl

        # 不明白
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())

        # 设置获取时间的函数
        self.time_func = time_func or time.time

        # self._handlers[fd] = (obj, stack_context.wrap(handler))
        # fd这个时候是一个数字,一般的时候是一个fd的对象
        self._handlers = {}

        # 保存每一次循环所得到的fd和事件对
        self._events = {}

        # 所有的callback函数的集合
        self._callbacks = []
        self._callback_lock = threading.Lock()

        # 所有需要延时执行的函数的集合
        self._timeouts = []

        self._cancellations = 0
        self._running = False  # IOLoop是不是已经运行了
        self._stopped = False  # IOLoop是不是已经停止了,为什么有两个
        self._closing = False
        self._thread_ident = None
        self._blocking_signal_threshold = None

        # Create a pipe that we send bogus data to when we want to wake
        # the I/O loop when it is idle
        # 这个真心不懂,以后研究
        self._waker = Waker()

        # 初始化的时候添加self._waker的一个读得socket到IOLoop里面
        self.add_handler(self._waker.fileno(),
                         lambda fd, events: self._waker.consume(),
                         self.READ)
Exemple #31
0
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either socket.AF_INET
    or socket.AF_INET6 to restrict to ipv4 or ipv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    ``socket.listen()``.
    """
    sockets = []
    if address == "":
        address = None
    flags = socket.AI_PASSIVE
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                  0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #32
0
 def bind_unix_socket(file, mode=0o600, backlog=128):
     sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
     set_close_exec(sock.fileno())
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     sock.setblocking(0)
     try:
         st = os.stat(file)
     except (OSError, err):
         if err.errno != errno.ENOENT:
             raise
     else:
         if stat.S_ISSOCK(st.st_mode):
             os.remove(file)
         else:
             raise ValueError("File %s exists and is not a socket", file)
     sock.bind(file)
     os.chmod(file, mode)
     sock.listen(backlog)
     return sock
    def __init__(self, impl=None):
        self._impl = impl or _poll()           # Linux下即epoll
        if hasattr(self._impl, 'fileno'):      # 若支持,设置FD_CLOEXEC
            set_close_exec(self._impl.fileno())

        self._callback_lock = threading.Lock() # 使self._callbacks可用于多线程

        self._handlers = {}      # epoll中每个fd的处理函数Map
        self._events = {}        # epoll返回的待处理事件Map
        self._callbacks = []     # 用户加入的回调函数列表
        self._timeouts = []      # ioloop中基于时间的调度,是一个小根堆

        self._running = False      # 标记ioloop已经调用了start,还未调用stop
        self._stopped = False      # 标记ioloop循环已退出,或已调用了stop
        self._thread_ident = None  # 标记ioloop所运行的线程,以支持多线程访问
        self._blocking_signal_threshold = None

        self._waker = Waker()    # 创建一个管道,用于在其他线程调用add_callback时唤醒epoll_wait
        self.add_handler(self._waker.fileno(), lambda fd, events: self._waker.consume(), self.READ)
Exemple #34
0
    def initialize(self, impl, time_func=None):
        super(PollIOLoop, self).initialize()

        # 使用的模型,使用的哪一个 select epoll kqueue
        # ubuntu系统使用的epoll
        self._impl = impl

        # 不明白
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())

        # 设置获取时间的函数
        self.time_func = time_func or time.time

        # self._handlers[fd] = (obj, stack_context.wrap(handler))
        # fd这个时候是一个数字,一般的时候是一个fd的对象
        self._handlers = {}

        # 保存每一次循环所得到的fd和事件对
        self._events = {}

        # 所有的callback函数的集合
        self._callbacks = []
        self._callback_lock = threading.Lock()

        # 所有需要延时执行的函数的集合
        self._timeouts = []

        self._cancellations = 0
        self._running = False  # IOLoop是不是已经运行了
        self._stopped = False  # IOLoop是不是已经停止了,为什么有两个
        self._closing = False
        self._thread_ident = None
        self._blocking_signal_threshold = None

        # Create a pipe that we send bogus data to when we want to wake
        # the I/O loop when it is idle
        # 这个真心不懂,以后研究
        self._waker = Waker()

        # 初始化的时候添加self._waker的一个读得socket到IOLoop里面
        self.add_handler(self._waker.fileno(),
                         lambda fd, events: self._waker.consume(), self.READ)
Exemple #35
0
def get_sockets_to_bind(port, address=None, family=socket.AF_UNSPEC, flags=None):

    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE


    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_DGRAM, 0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if e.args[0] == errno.EAFNOSUPPORT:
                continue
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(False)
        sock.bind(sockaddr)
        sockets.append(sock)

    return sockets
Exemple #36
0
    def __init__(self, impl=None):
        self._impl = impl or _poll() # self._impl默认是select.epoll()
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())

        self._callback_lock = threading.Lock() # 回调锁

        self._handlers = {} # 处理函数集合
        self._events = {}
        self._callbacks = [] # 回调函数集合
        self._timeouts = [] # 基于时间的调度,_timeouts是个堆

        self._running = False # 运行标志
        self._stopped = False
        self._thread_ident = None
        self._blocking_signal_threshold = None

        # 创建一个管道,当我们想在ioloop空闲时唤醒它就通过管道发送假的数据
        self._waker = Waker()
        self.add_handler(self._waker.fileno(), lambda fd, events: self._waker.consume(), self.READ)
Exemple #37
0
def bind_udp_socket(port,
                    address=None,
                    family=socket.AF_UNSPEC,
                    backlog=_DEFAULT_BACKLOG,
                    flags=None):
    '''
    '''
    udp_sockets = []
    if address == '':
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        family = socket.AFINET
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None
    for res in socket.getaddrinfo(address, port, family, socket.SOCK_DGRAM, 0,
                                  flags):
        af, socktype, proto, canonname, sockaddr = res
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            if hasattr(socket, 'IPPROTO_IPV6'):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 & IPv6
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))
        sock.setblocking(0)
        sock.bind(sockaddr)
        bound_port = sock.getsockname()[1]
        udp_sockets.append(sock)
    return udp_sockets
Exemple #38
0
def bind_sockets(port, address=None, family=socket.AF_INET, backlog=128):
    sockets = []
    if address == '':
        address = None
    flags = socket.AI_PASSIVE
    if hasattr(socket, 'AI_ADDRCONFIG'):
        flags |= socket.AI_ADDRCONFIG
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_DGRAM, 0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            if hasattr(socket, 'IPPROTO_IPV6'):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        # sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #39
0
    def initialize(self, impl, time_func=None):
        super(PollIOLoop, self).initialize()
        self._impl = impl
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())
        self.time_func = time_func or time.time
        self._handlers = {}
        self._events = {}
        self._callbacks = []
        self._callback_lock = threading.Lock()
        self._timeouts = []
        self._running = False
        self._stopped = False
        self._thread_ident = None
        self._blocking_signal_threshold = None

        # Create a pipe that we send bogus data to when we want to wake
        # the I/O loop when it is idle
        self._waker = Waker()
        self.add_handler(self._waker.fileno(),
                         lambda fd, events: self._waker.consume(), self.READ)
Exemple #40
0
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=25):
    sockets = []
    if address == "":
        address = None
    flags = socket.AI_PASSIVE
    if hasattr(socket, "AI_ADDRCONFIG"):
        flags |= socket.AI_ADDRCONFIG
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_DGRAM,
                                  0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        sock = socket.socket(af, socktype, proto)
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
        sock.setblocking(0)
        sock.bind(sockaddr)
        sockets.append(sock)
    return sockets
Exemple #41
0
    def _create_stream(self,
                       max_buffer_size,
                       af,
                       addr,
                       source_ip=None,
                       source_port=None):
        # Always connect in plaintext; we'll convert to ssl if necessary
        # after one connection has completed.
        source_port_bind = source_port if isinstance(source_port, int) else 0
        source_ip_bind = source_ip
        if source_port_bind and not source_ip:
            # User required a specific port, but did not specify
            # a certain source IP, will bind to the default loopback.
            source_ip_bind = '::1' if af == socket.AF_INET6 else '127.0.0.1'
            # Trying to use the same address family as the requested af socket:
            # - 127.0.0.1 for IPv4
            # - ::1 for IPv6
        socket_obj = socket.socket(af)
        set_close_exec(socket_obj.fileno())
        try:
            stream = IOStream(socket_obj,
                              io_loop=self.io_loop,
                              max_buffer_size=max_buffer_size)
        except socket.error as e:
            fu = Future()
            fu.set_exception(e)
            return fu
        else:
            if source_port_bind or source_ip_bind:

                @gen.coroutine
                def _(addr):
                    r = yield stream.connect(
                        (source_ip_bind, source_port_bind))
                    yield self._connect_tunnel(stream, addr, {})
                    raise gen.Return(r)

                return _(addr)
            else:
                return stream.connect(addr)
Exemple #42
0
    def initialize(self, impl, time_func=None, **kwargs):
        super(PollIOLoop, self).initialize(**kwargs)
        self._impl = impl
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())
        self.time_func = time_func or time.time
        self._handlers = {}
        self._events = {}
        self._callbacks = []
        self._callback_lock = threading.Lock()
        self._timeouts = []
        self._cancellations = 0
        self._running = False
        self._stopped = False
        self._closing = False
        self._thread_ident = None
        self._blocking_signal_threshold = None
        self._timeout_counter = itertools.count()

        self._waker = Waker()
        self.add_handler(self._waker.fileno(),
                         lambda fd, events: self._waker.consume(), self.READ)
Exemple #43
0
    def _create_stream(
            self,
            max_buffer_size: int,
            af: socket.AddressFamily,
            addr: Tuple,
            source_ip: str = None,
            source_port: int = None,
    ) -> Tuple[IOStream, "Future[IOStream]"]:

        # Always connect in plaintext; we'll convert to ssl if necessary
        # after one connection has completed.
        source_port_bind = source_port if isinstance(source_port, int) else 0
        source_ip_bind = source_ip
        if source_port_bind and not source_ip:
            # User required a specific port, but did not specify
            # a certain source IP, will bind to the default loopback.
            source_ip_bind = "::1" if af == socket.AF_INET6 else "127.0.0.1"
            # Trying to use the same address family as the requested af socket:
            # - 127.0.0.1 for IPv4
            # - ::1 for IPv6
        socket_obj = socket.socket(af)
        set_close_exec(socket_obj.fileno())
        if source_port_bind or source_ip_bind:
            # If the user requires binding also to a specific IP/port.
            try:
                socket_obj.bind((source_ip_bind, source_port_bind))
            except socket.error:
                socket_obj.close()
                # Fail loudly if unable to use the IP/port.
                raise
        try:
            stream = IOStream(socket_obj, max_buffer_size=max_buffer_size)
        except socket.error as e:
            fu = Future()  # type: Future[IOStream]
            fu.set_exception(e)
            return stream, fu
        else:
            return stream, stream.connect(addr)
Exemple #44
0
    def __init__(self,
                 listener,
                 application=None,
                 backlog=2048,
                 socket_type=socket.SOCK_STREAM,
                 address_family=socket.AF_INET,
                 **kw):
        self.address_family = address_family
        self.socket_type = socket_type
        host, port = listener

        if (isinstance(application, Application)
                and not isinstance(application, WSGIApplication)):
            self._server = HTTPServer(application)
        elif isinstance(application, TCPServer):
            self._server = application
        elif callable(application):
            tapp = tornado.wsgi.WSGIContainer(application)
            self._server = HTTPServer(tapp)
        else:
            raise TypeError("Unsupported application type: %r" %
                            (application, ))

        if host.startswith('fd://'):
            fd = int(host.split('://')[1])
            set_close_exec(fd)
            sock = socket.fromfd(fd, address_family, socket_type)
            sock.setblocking(0)
            socks = [sock]
        elif self.address_family == socket.AF_UNIX:
            filename = host[len('unix:'):]
            sock = tornado.netutil.bind_unix_socket(filename, backlog=backlog)
            socks = [sock]
        else:
            socks = tornado.netutil.bind_sockets(port, host, address_family,
                                                 backlog)
        self._server.add_sockets(socks)
        self.application = application
Exemple #45
0
    def initialize(self, impl, time_func=None, **kwargs):
        super(PollIOLoop, self).initialize(**kwargs)
        self._impl = impl
        if hasattr(self._impl, 'fileno'):
            set_close_exec(self._impl.fileno())
        self.time_func = time_func or time.time
        self._handlers = {}
        self._events = {}
        self._callbacks = collections.deque()
        self._timeouts = []
        self._cancellations = 0
        self._running = False
        self._stopped = False
        self._closing = False
        self._thread_ident = None
        self._blocking_signal_threshold = None
        self._timeout_counter = itertools.count()

        # Create a pipe that we send bogus data to when we want to wake
        # the I/O loop when it is idle
        self._waker = Waker()
        self.add_handler(self._waker.fileno(),
                         lambda fd, events: self._waker.consume(), self.READ)
Exemple #46
0
def bind_udp_socket(port, address=None, family=socket.AF_UNSPEC, backlog=_DEFAULT_BACKLOG, flags=None):
    '''
    '''
    udp_sockets = []
    if address == '':
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None
    for res in socket.getaddrinfo(address, port, family, socket.SOCK_DGRAM, 0, flags):
        af, socktype, proto, canonname, sockaddr = res
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            if hasattr(socket, 'IPPROTO_IPV6'):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 & IPv6 
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))
        sock.setblocking(0)
        sock.bind(sockaddr)
        bound_port = sock.getsockname()[1]
        udp_sockets.append(sock)
    return udp_sockets
Exemple #47
0
        sockets.append(sock)
    return sockets

if hasattr(socket, 'AF_UNIX'):
    def bind_unix_socket(file, mode=0600, backlog=128):
        """Creates a listening unix socket.

        If a socket with the given name already exists, it will be deleted.
        If any other file with that name exists, an exception will be
        raised.

        Returns a socket object (not a list of socket objects like
        `bind_sockets`)
        """
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        set_close_exec(sock.fileno())
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.setblocking(0)
        try:
            st = os.stat(file)
        except OSError, err:
            if err.errno != errno.ENOENT:
                raise
        else:
            if stat.S_ISSOCK(st.st_mode):
                os.remove(file)
            else:
                raise ValueError("File %s exists and is not a socket", file)
        sock.bind(file)
        os.chmod(file, mode)
        sock.listen(backlog)
Exemple #48
0
def bind_sockets(port,
                 address=None,
                 family=socket.AF_UNSPEC,
                 backlog=128,
                 flags=None):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.
    """
    # bind_sockets 方法在 netutil.py 里被定义,没什么难的,创建监听 socket 后为了[异步],
    # 设置 socket 为非阻塞(这样由它 accept 派生的socket 也是非阻塞的),
    # 然后绑定并监听之。
    # add_sockets 方法接收 socket 列表,对于列表中的 socket,用 fd 作键记录下来,
    # 并调用add_accept_handler 方法。它也是在 netutil 里定义的,

    # bind_socket完成的工作包括:(1):创建socket,绑定socket到指定的地址和端口,(2)开启侦听。
    # 函数参数说明:
    # 1.port不用说,端口号嘛。
    # 2.address可以是IP地址,如“192.168.1.100”,也可以是hostname,比如“localhost”。
    # 如果是hostname,则可以监听该hostname对应的【所有IP】。
    # 如果address是空字符串(“”)或者None,则会监听主机上的【所有接口】。
    # 3.family是指网络层协议类型。可以选AF_INET和AF_INET6,默认情况下则两者都会被启用。
    # 这个参数就是在BSD Socket创建时的那个sockaddr_in.sin_family参数。
    # 4.backlog就是指【侦听队列的长度】,即BSD listen(n)中的那个n。
    # 5.flags参数是一些位标志,它是用来传递给socket.getaddrinfo()函数的。比如socket.AI_PASSIVE等。
    # 另外要注意,在IPV6和IPV4【混用】的情况下,这个函数的返回值可以是一个socket列表,
    # 因为这时候一个address参数可能对应一个IPv4地址和一个IPv6地址,它们的socket是【不通用的】,会各自独立创建。

    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    # 闹半天,前面解释的参数全都被[socket.getaddrinfo()]这个函数吃下去了
    # socket.getaddrinfo()是python标准库中的函数,
    # 它的作用是将所接收的参数【重组】为一个结构res,
    # res的【类型】将可以直接作为【socket.socket()】的参数。跟BSD Socket中的getaddrinfo差不多嘛。

    # 之所以用了一个循环,正如前面讲到的,因为IPv6和IPv4【混用】的情况下,
    # getaddrinfo会返回【多个地址】的信息。参见python文档中的说明和示例:
    # The function returns a list of 5-tuples with the following structure: (family, type, proto, canonname, sockaddr)
    # >>> socket.getaddrinfo("www.python.org", 80, proto=socket.SOL_TCP)
    # [(2, 1, 6, '', ('82.94.164.162', 80)),
    #  (10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]

    for res in set(
            socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0,
                               flags)):
        # 对 getaddrinfo的详细解释
        # getaddrinfo返回服务器的所有【网卡信息】, 每块网卡上都要【创建监听客户端的请求】并【返回】
        # 创建的sockets。
        # 创建socket过程中绑定【地址和端口】,同时设置了fcntl.FD_CLOEXEC(创建子进程时关闭打开的socket)和
        # socket.SO_REUSEADDR(保证某一socket关闭后立即释放端口,实现端口复用)标志位。
        # sock.listen(backlog=128)默认设定等待被处理的连接最大个数为128。
        # getaddrinfo(host, port [, family, socktype, proto, flags])
        # -> list of (family, socktype, proto, canonname, sockaddr)
        # Resolve host and port into addrinfo struct.
        # 接下来的代码在循环体中,是针对单个地址的。循环体内一开始就如我们猜想,直接拿getaddrinfo的返回值
        # 来创建socket。
        # 先从tuple中拆出5个参数,然后拣需要的来创建socket。
        af, socktype, proto, canonname, sockaddr = res
        try:
            # 创建 socket
            #
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if e.args[0] == errno.EAFNOSUPPORT:
                continue
            raise
        # 此行暂未理解(3.5/21:50)
        # 同时设置了fcntl.FD_CLOEXEC(创建子进程时关闭打开的socket)
        set_close_exec(sock.fileno())
        # 这行是设置进程退出时对sock的操作。lose_on_exec 是一个进程所有文件描述符
        # (文件句柄)的位图标志,每个比特位代表一个打开的文件描述符,
        # 用于确定在调用系统调用execve()时需要关闭的文件句柄(参见include/fcntl.h)。
        # 当一个程序使用fork()函数创建了一个子进程时,通常会在该子进程中调用execve()函数加载执行另一个新程序。
        # 此时子进程将完全被新程序替换掉,并在子进程中开始执行新程序。
        # 若一个文件描述符在close_on_exec中的对应比特位被设置,
        # 那么在执行execve()时该描述符将被关闭,否则该描述符将始终处于打开状态。

        # 当打开一个文件时,默认情况下文件句柄在子进程中也处于打开状态。因此sys_open()中要复位对应比特位。
        if os.name != 'nt':
            # socket.SO_REUSEADDR(保证某一socket关闭后立即释放端口,实现端口复用)标志位。
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 对非NT的内核,需要额外设置一个SO_REUSEADDR参数。有些系统的设计里,
            # 服务器进程结束后端口也会被内核保持一段时间,若我们迅速的重启服务器,
            # 可能会遇到“端口已经被占用”的情况。
            # 这个标志就是通知内核不要保持了,进程一关,立马放手,便于后来者重用
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # 每创建一个socket都添加到前面定义的sockets = []列表中,函数结束后,将列表返回;但为啥不是tcpserver的成员呢?
        # 网上都说nginx和lighthttpd是高性能web服务器,而tornado也是著名的高抗负载应用,它们间有什么相似处呢?
        # 上节提到的ioloop对象是如何循环的呢?往下看
        # 首先关于TCP服务器的开发上节已经提过,很明显那个【三段式】的示例是个效率很低的
        # (因为只有一个连接被端开新连接才能被接受)。要想开发高性能的服务器,就得在这【accept】上下功夫。

        # 首先,新连接的到来一般是经典的【三次握手】,只有当服务器收到一个SYN时才说明有一个新连接(还没建立),
        # 这时监听[fd是可读的]可以调用accept,此前服务器可以干点别的,这就是SELECT/POLL/EPOLL的思路。
        # 而只有三次握手成功后,accept才会返回,此时监听fd是读完成状态,似乎服务器在此之前可以转身去干别的,
        # 等到读完成再调用accept就不会有延迟了,这就是AIO的思路,不过在*nix平台上好像支持不是很广。。。
        # 再有,accept得到的新fd,不一定是可读的(客户端请求还没到达),所以可以等新fd可读时在read()
        # (可能会有一点延迟),也可以用AIO等读完后再read就不会延迟了。同样类似,对于write,close也有类似的事件。
        # 总的思路就是,在我们关心的fd上注册关心的多个事件,事件发生了就【启动回调】,没发生就看点别的。这是单线程的,
        # 多线程的复杂一点,但差不多。nginx和lightttpd以及tornado都是类似的方式,
        # 只不过是多进程和多线程或单线程的区别而已。为简便,我们只分析tornado单线程的情况

        # 设置为非阻塞的
        sock.setblocking(0)
        # 创建完socket后第一步就是bind(绑定端口地址)
        sock.bind(sockaddr)
        # 绑定完就是要监听;默认设定等待被处理的连接最大个数为128。
        # 最大阻塞数量
        sock.listen(backlog)
        # 把监听到的socket对象添加到socket列表中
        sockets.append(sock)
    return sockets
Exemple #49
0
def bind_sockets_with_reuseport(port, address=None, family=socket.AF_UNSPEC,
                                backlog=_DEFAULT_BACKLOG, flags=None):
    # it's just a plain copy from tornado, but it sets SO_REUSEPORT
    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                      0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        if (sys.platform == 'darwin' and address == 'localhost' and
                af == socket.AF_INET6 and sockaddr[3] != 0):
            # Mac OS X includes a link-local address fe80::1%lo0 in the
            # getaddrinfo results for 'localhost'.  However, the firewall
            # doesn't understand that this is a local address and will
            # prompt for access (often repeatedly, due to an apparent
            # bug in its ability to remember granting access to an
            # application). Skip these addresses.
            continue
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

            # I assume that MacOS has a new version of Python
            if hasattr(socket, "SO_REUSEPORT"):
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
            else:
                if sys.platform.startswith('darwin'):
                    raise SystemError("Update your python version")
                # <socket.h> #define SO_REUSEPORT  15
                sock.setsockopt(socket.SOL_SOCKET, 15, 1)

        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 and IPv6
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))

        sock.setblocking(0)
        sock.bind(sockaddr)
        bound_port = sock.getsockname()[1]
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #50
0
def bind_sockets(
    port: int,
    address: Optional[str] = None,
    family: socket.AddressFamily = socket.AF_UNSPEC,
    backlog: int = _DEFAULT_BACKLOG,
    flags: Optional[int] = None,
    reuse_port: bool = False,
) -> List[socket.socket]:
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.

    ``reuse_port`` option sets ``SO_REUSEPORT`` option for every socket
    in the list. If your platform doesn't support this option ValueError will
    be raised.
    """
    if reuse_port and not hasattr(socket, "SO_REUSEPORT"):
        raise ValueError("the platform doesn't support SO_REUSEPORT")

    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None
    unique_addresses = set()  # type: set
    for res in sorted(
        socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0, flags),
        key=lambda x: x[0],
    ):
        if res in unique_addresses:
            continue

        unique_addresses.add(res)

        af, socktype, proto, canonname, sockaddr = res
        if (
            sys.platform == "darwin"
            and address == "localhost"
            and af == socket.AF_INET6
            and sockaddr[3] != 0
        ):
            # Mac OS X includes a link-local address fe80::1%lo0 in the
            # getaddrinfo results for 'localhost'.  However, the firewall
            # doesn't understand that this is a local address and will
            # prompt for access (often repeatedly, due to an apparent
            # bug in its ability to remember granting access to an
            # application). Skip these addresses.
            continue
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != "nt":
            try:
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            except socket.error as e:
                if errno_from_exception(e) != errno.ENOPROTOOPT:
                    # Hurd doesn't support SO_REUSEADDR.
                    raise
        if reuse_port:
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 and IPv6
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))

        sock.setblocking(False)
        try:
            sock.bind(sockaddr)
        except OSError as e:
            if (
                errno_from_exception(e) == errno.EADDRNOTAVAIL
                and address == "localhost"
                and sockaddr[0] == "::1"
            ):
                # On some systems (most notably docker with default
                # configurations), ipv6 is partially disabled:
                # socket.has_ipv6 is true, we can create AF_INET6
                # sockets, and getaddrinfo("localhost", ...,
                # AF_PASSIVE) resolves to ::1, but we get an error
                # when binding.
                #
                # Swallow the error, but only for this specific case.
                # If EADDRNOTAVAIL occurs in other situations, it
                # might be a real problem like a typo in a
                # configuration.
                sock.close()
                continue
            else:
                raise
        bound_port = sock.getsockname()[1]
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #51
0
def _pipe_cloexec():
    r, w = os.pipe()
    set_close_exec(r)
    set_close_exec(w)
    return r, w
Exemple #52
0
        sockets.append(sock)
    return sockets

if hasattr(socket, 'AF_UNIX'):
    def bind_unix_socket(file, mode=0600, backlog=128):
        """Creates a listening unix socket.

        If a socket with the given name already exists, it will be deleted.
        If any other file with that name exists, an exception will be
        raised.

        Returns a socket object (not a list of socket objects like
        `bind_sockets`)
        """
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        set_close_exec(sock.fileno())
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.setblocking(0)
        try:
            st = os.stat(file)
        except OSError, err:
            if err.errno != errno.ENOENT:
                raise
        else:
            if stat.S_ISSOCK(st.st_mode):
                os.remove(file)
            else:
                raise ValueError("File %s exists and is not a socket", file)
        sock.bind(file)
        os.chmod(file, mode)
        sock.listen(backlog)
Exemple #53
0
def bind_sockets(port, address=None, family=socket.AF_UNSPEC,
                 backlog=_DEFAULT_BACKLOG, flags=None):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.
    """
    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                      0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        if (sys.platform == 'darwin' and address == 'localhost' and
                af == socket.AF_INET6 and sockaddr[3] != 0):
            # Mac OS X includes a link-local address fe80::1%lo0 in the
            # getaddrinfo results for 'localhost'.  However, the firewall
            # doesn't understand that this is a local address and will
            # prompt for access (often repeatedly, due to an apparent
            # bug in its ability to remember granting access to an
            # application). Skip these addresses.
            continue
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            try:
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            except socket.error as e:
                if e.args[0] != errno.ENOPROTOOPT:
                    raise
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 and IPv6
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))

        sock.setblocking(0)
        sock.bind(sockaddr)
        bound_port = sock.getsockname()[1]
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #54
0
def bind_sockets(
    port: int,
    address: str = None,
    family: socket.AddressFamily = socket.AF_UNSPEC,
    backlog: int = _DEFAULT_BACKLOG,
    flags: int = None,
    reuse_port: bool = False,
) -> List[socket.socket]:
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.

    ``reuse_port`` option sets ``SO_REUSEPORT`` option for every socket
    in the list. If your platform doesn't support this option ValueError will
    be raised.

    family: 表示socket使用的协议簇 AF_UNIX(本机通信)/AF_INET(TCP/IP协议簇中的IPv4协议)/AF_INET6(TCP/IP协议簇中的IPv4协议)
    sockettype:表示socket的类型
    proto:顾名思义,就是指定协议  IPPROTO_TCP(=6)和IPPTOTO_UDP(=17),它们分别对应TCP传输协议、UDP传输协议。
    """
    if reuse_port and not hasattr(socket, "SO_REUSEPORT"):
        raise ValueError("the platform doesn't support SO_REUSEPORT")

    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None
    unique_addresses = set()  # type: set
    for res in sorted(
            socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0,
                               flags),
            key=lambda x: x[0],
    ):  # 这又是什么神仙写法
        if res in unique_addresses:
            continue

        unique_addresses.add(res)

        af, socktype, proto, canonname, sockaddr = res
        if (sys.platform == "darwin" and address == "localhost"
                and af == socket.AF_INET6 and sockaddr[3] != 0):
            # Mac OS X includes a link-local address fe80::1%lo0 in the
            # getaddrinfo results for 'localhost'.  However, the firewall
            # doesn't understand that this is a local address and will
            # prompt for access (often repeatedly, due to an apparent
            # bug in its ability to remember granting access to an
            # application). Skip these addresses.
            continue
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != "nt":
            try:
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            except socket.error as e:
                if errno_from_exception(e) != errno.ENOPROTOOPT:
                    # Hurd doesn't support SO_REUSEADDR.
                    raise
        if reuse_port:
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 and IPv6
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))

        sock.setblocking(False)  # 创建socket.socket后设置为非阻塞连接
        sock.bind(sockaddr)  # 绑定address
        bound_port = sock.getsockname()[1]
        sock.listen(backlog)
        sockets.append(sock)
        # print(sockets)
        """
        总体来说就是创建socket然后绑定bind某个address,并启动监听list。那么这样看来服务就是启动了咯???
        不是把==服务居然已经起来了,后面还有啥事??? 启动之后直接挂掉了==好像是这么个理
        因为非阻塞,好像确实会直接走掉,非阻塞还可以使用accept来获取目标
        """
    return sockets
def bind_sockets(port, address=None, family=socket.AF_UNSPEC,
                 backlog=_DEFAULT_BACKLOG, flags=None):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.
    """
    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        #
        # 由于可以通过指定编译选项来编译出仅支持 ipv4 的 python 版本,为了保证
        # getaddrinfo 也只返回 ipv4 的地址,所以这里指定 socket.AF_INET
        family = socket.AF_INET

    # 函数注释中已经有说明了,flag 是一个传递给 getaddrinfo 函数的 AI_* 掩码。常用的如
    # ``socket.AI_PASSIVE | socket.AI_CANNONAME | socket.AI_NUMERICHOST``。
    # ``socket.AI_PASSIVE``: 指示函数返回的地址将用于 bind() 函数调用,否则用于 connect() 函数调用;
    # ``socket.AI_CANNONAME``: 指示函数返回的地址需要一个规范名(而不是别名)。
    # ``socket.AI_NUMERICHOST``: 指示函数返回数字格式的地址。
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None

    # socket.getaddrinfo(host, port[, family[, socktype[, proto[, flags]]]])
    # family: 协议簇,常用的协议包括 AF_UNIX(1,本机通信)/AF_INET(2,IPV4)/AF_INET6(10,IPV6)。
    # socktype:socket 的类型,常见的socket类型包括SOCK_STREAM(TCP流)/SOCK_DGRAM(UDP数据报)/SOCK_RAW(原始套接字)。
    #           其中,SOCK_STREAM=1,SOCK_DGRAM=2,SOCK_RAW=3。
    # proto:协议,套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP(=6) 和
    #        IPPTOTO_UDP(=17),它们分别对应 TCP 传输协议、UDP 传输协议。与 IP 数据包的 ``8位协议字段`` 对应。
    for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
                                      0, flags)):
        af, socktype, proto, canonname, sockaddr = res
        if (platform.system() == 'Darwin' and address == 'localhost' and
                af == socket.AF_INET6 and sockaddr[3] != 0):
            # Mac OS X includes a link-local address fe80::1%lo0 in the
            # getaddrinfo results for 'localhost'.  However, the firewall
            # doesn't understand that this is a local address and will
            # prompt for access (often repeatedly, due to an apparent
            # bug in its ability to remember granting access to an
            # application). Skip these addresses.
            #
            # address = 'localhost' 时 Mac OS X 可能会返回一个 ipv6 地址 fe80::1%lo0,
            # 而防火墙不能识别出这是一个本地地址而尝试访问会导致 bug ,所以这里忽略这个地址。
            # ipv6  二进制 128 位,以 16 位为一组,每组以 `:` 分开,`::` 表示一组0或者多组连续的0,
            # 但是只能出现 1 次。
            # sockaddr is a tuple describing a socket address, whose format
            # depends on the returned family (a (address, port) 2-tuple for
            # AF_INET, a (address, port, flow info, scope id) 4-tuple for AF_INET6)
            continue
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        # 为 fd 设置 FD_CLOEXEC 标识
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            # 避免在服务器重启的时候发生“该地址以被使用”这种错误。
            # socket.SOL_SOCKET 指定在套接字级别设置 `可选项`。
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 and IPv6
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))

        sock.setblocking(0)
        sock.bind(sockaddr)
        bound_port = sock.getsockname()[1]
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #56
0
def _pipe_cloexec() -> Tuple[int, int]:
    r, w = os.pipe()
    set_close_exec(r)
    set_close_exec(w)
    return r, w
Exemple #57
0
def bind_sockets(port,
                 address=None,
                 family=socket.AF_UNSPEC,
                 backlog=_DEFAULT_BACKLOG,
                 flags=None,
                 reuse_port=False):
    """Creates listening sockets bound to the given port and address.

    Returns a list of socket objects (multiple sockets are returned if
    the given address maps to multiple IP addresses, which is most common
    for mixed IPv4 and IPv6 use).

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen() <socket.socket.listen>`.

    ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
    ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.

    ``reuse_port`` option sets ``SO_REUSEPORT`` option for every socket
    in the list. If your platform doesn't support this option ValueError will
    be raised.
    """
    if reuse_port and not hasattr(socket, "SO_REUSEPORT"):
        raise ValueError("the platform doesn't support SO_REUSEPORT")

    sockets = []
    if address == "":
        address = None
    if not socket.has_ipv6 and family == socket.AF_UNSPEC:
        # Python can be compiled with --disable-ipv6, which causes
        # operations on AF_INET6 sockets to fail, but does not
        # automatically exclude those results from getaddrinfo
        # results.
        # http://bugs.python.org/issue16208
        family = socket.AF_INET
    if flags is None:
        flags = socket.AI_PASSIVE
    bound_port = None
    for res in set(
            socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0,
                               flags)):
        af, socktype, proto, canonname, sockaddr = res
        if (sys.platform == 'darwin' and address == 'localhost'
                and af == socket.AF_INET6 and sockaddr[3] != 0):
            # Mac OS X includes a link-local address fe80::1%lo0 in the
            # getaddrinfo results for 'localhost'.  However, the firewall
            # doesn't understand that this is a local address and will
            # prompt for access (often repeatedly, due to an apparent
            # bug in its ability to remember granting access to an
            # application). Skip these addresses.
            continue
        try:
            sock = socket.socket(af, socktype, proto)
        except socket.error as e:
            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                continue
            raise
        set_close_exec(sock.fileno())
        if os.name != 'nt':
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if reuse_port:
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        if af == socket.AF_INET6:
            # On linux, ipv6 sockets accept ipv4 too by default,
            # but this makes it impossible to bind to both
            # 0.0.0.0 in ipv4 and :: in ipv6.  On other systems,
            # separate sockets *must* be used to listen for both ipv4
            # and ipv6.  For consistency, always disable ipv4 on our
            # ipv6 sockets and use a separate ipv4 socket when needed.
            #
            # Python 2.x on windows doesn't have IPPROTO_IPV6.
            if hasattr(socket, "IPPROTO_IPV6"):
                sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

        # automatic port allocation with port=None
        # should bind on the same port on IPv4 and IPv6
        host, requested_port = sockaddr[:2]
        if requested_port == 0 and bound_port is not None:
            sockaddr = tuple([host, bound_port] + list(sockaddr[2:]))

        sock.setblocking(0)
        sock.bind(sockaddr)
        bound_port = sock.getsockname()[1]
        sock.listen(backlog)
        sockets.append(sock)
    return sockets
Exemple #58
0
def _pipe_cloexec():
    r, w = os.pipe()
    set_close_exec(r)
    set_close_exec(w)
    return r, w