]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Pull socket creation out of HTTPServer into a new module.
authorBen Darnell <ben@bendarnell.com>
Mon, 4 Jul 2011 22:58:17 +0000 (15:58 -0700)
committerBen Darnell <ben@bendarnell.com>
Mon, 4 Jul 2011 22:58:17 +0000 (15:58 -0700)
tornado/httpserver.py
tornado/netutil.py [new file with mode: 0644]
tornado/test/import_test.py
website/sphinx/netutil.rst [new file with mode: 0644]
website/sphinx/networking.rst

index c36e3bf2bf7ddad80a2518a4929d914fd31d9bb3..8c3467c583c9af4da43239f23f50829124c2b009 100644 (file)
@@ -35,6 +35,7 @@ from tornado.escape import utf8, native_str, parse_qs_bytes
 from tornado import httputil
 from tornado import ioloop
 from tornado import iostream
+from tornado import netutil
 from tornado import stack_context
 from tornado.util import b, bytes_type
 
@@ -184,37 +185,9 @@ class HTTPServer(object):
         This method may be called multiple times prior to start() to listen
         on multiple ports or interfaces.
         """
-        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 socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
-                                      0, flags):
-            af, socktype, proto, canonname, sockaddr = res
-            sock = socket.socket(af, socktype, proto)
-            flags = fcntl.fcntl(sock.fileno(), fcntl.F_GETFD)
-            flags |= fcntl.FD_CLOEXEC
-            fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, flags)
-            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 = netutil.bind_sockets(port, address=address,
+                                       family=family, backlog=backlog)
+        for sock in sockets:
             self._sockets[sock.fileno()] = sock
             if self._started:
                 self.io_loop.add_handler(sock.fileno(), self._handle_events,
diff --git a/tornado/netutil.py b/tornado/netutil.py
new file mode 100644 (file)
index 0000000..dad17ce
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 Facebook
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Miscellaneous network utility code."""
+
+import os
+import socket
+
+try:
+    import fcntl
+except ImportError:
+    if os.name == 'nt':
+        from tornado import win32_support as fcntl
+    else:
+        raise
+
+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 socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
+                                  0, flags):
+        af, socktype, proto, canonname, sockaddr = res
+        sock = socket.socket(af, socktype, proto)
+        flags = fcntl.fcntl(sock.fileno(), fcntl.F_GETFD)
+        flags |= fcntl.FD_CLOEXEC
+        fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, flags)
+        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
index 3b6d3f794c2fc7dac59a40c21a76f8f3ec811905..a94c111ee9a5eeb80383fd9c85d274f3c9a027ab 100644 (file)
@@ -17,6 +17,7 @@ class ImportTest(unittest.TestCase):
         import tornado.iostream
         import tornado.locale
         import tornado.options
+        import tornado.netutil
         import tornado.simple_httpclient
         import tornado.stack_context
         import tornado.template
diff --git a/website/sphinx/netutil.rst b/website/sphinx/netutil.rst
new file mode 100644 (file)
index 0000000..f7a0e0d
--- /dev/null
@@ -0,0 +1,5 @@
+``tornado.netutil`` --- Miscellaneous network utilities
+=======================================================
+
+.. automodule:: tornado.netutil
+   :members:
index e77622dc579b3486cac78be257764dcf495013aa..f71de718ae1426af05d9eb5f0821c3904c459681 100644 (file)
@@ -6,3 +6,4 @@ Asynchronous networking
    ioloop
    iostream
    httpclient
+   netutil