From: Ben Darnell Date: Mon, 4 Jul 2011 22:58:17 +0000 (-0700) Subject: Pull socket creation out of HTTPServer into a new module. X-Git-Tag: v2.1.0~125 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=767d83d5c17233c01527617d66409aec2f3173bc;p=thirdparty%2Ftornado.git Pull socket creation out of HTTPServer into a new module. --- diff --git a/tornado/httpserver.py b/tornado/httpserver.py index c36e3bf2b..8c3467c58 100644 --- a/tornado/httpserver.py +++ b/tornado/httpserver.py @@ -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 index 000000000..dad17cea6 --- /dev/null +++ b/tornado/netutil.py @@ -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 diff --git a/tornado/test/import_test.py b/tornado/test/import_test.py index 3b6d3f794..a94c111ee 100644 --- a/tornado/test/import_test.py +++ b/tornado/test/import_test.py @@ -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 index 000000000..f7a0e0d20 --- /dev/null +++ b/website/sphinx/netutil.rst @@ -0,0 +1,5 @@ +``tornado.netutil`` --- Miscellaneous network utilities +======================================================= + +.. automodule:: tornado.netutil + :members: diff --git a/website/sphinx/networking.rst b/website/sphinx/networking.rst index e77622dc5..f71de718a 100644 --- a/website/sphinx/networking.rst +++ b/website/sphinx/networking.rst @@ -6,3 +6,4 @@ Asynchronous networking ioloop iostream httpclient + netutil